android-aidl 从懵逼开始

来源:互联网 发布:瘦腿 知乎 编辑:程序博客网 时间:2024/05/19 16:05
  1. 什么是aidl?
  2. aidl 能干什么?
  3. 怎么用 aidl?
  4. 实现一个最简单的aidl

以上4个问题,前面两个我不打算展开,我相信,关于这两个问题的说明和解答,已经有无数的大神详细的讲解过了。关于后面的两个问题,是我一直关心的问题。到刚才,我解决了第四个问题,但是第三个的话,我相信,得继续深入才能更好的回答。

好了,现在就开始第四个问题的实现。

  • 简单说明一下,最简单的aidl实现,不需要多个app,也不需要多个module。只要一个service,一个activity,一个.aidl文件。
  • 但是,我不打算一开始就去实现最简单的aidl模型,我准备先写一个最简单的bindService,作为过渡。一来,温习一下基础知识,二来,这个本身就是最简单的aidl的前奏,必不可少。

那么,如何实现呢?还是从代码下手吧。

  • 我先创建两个activity和一个service.activity为什么是两个?其实可以是一个,但是个人习惯,第一个总是作为入口,不做任何的真正逻辑,仅仅是作为目录和指引的作用。第二个是和服务对应的。也就是服务的调用者。清单文件如下:
  1. <application 
  2.         android:allowBackup="true" 
  3.         android:icon="@mipmap/ic_launcher" 
  4.         android:label="@string/app_name" 
  5.         android:supportsRtl="true" 
  6.         android:theme="@style/AppTheme" > 
  7.         <activity android:name=".activity.LauncherActivity" > 
  8.             <intent-filter> 
  9.                 <action android:name="android.intent.action.MAIN" /> 
  10.  
  11.                 <category android:name="android.intent.category.LAUNCHER" /> 
  12.             </intent-filter> 
  13.         </activity> 
  14.  
  15.         <service 
  16.             android:name=".service.NormalService" 
  17.             android:enabled="true" 
  18.             android:exported="true" /> 
  19.  
  20.         <activity 
  21.             android:theme="@style/AppTheme.NoActionbar" 
  22.             android:name=".activity.NormalActivity" > 
  23.         </activity> 
  24.     </application>
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".activity.LauncherActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".service.NormalService" android:enabled="true" android:exported="true" /> <activity android:theme="@style/AppTheme.NoActionbar" android:name=".activity.NormalActivity" > </activity> </application>

简单明了,我也没有任何的解释了。关于service上设置的两个属性分别是什么意思?我也不太了解。想了解的,可以自行搜索下,这个不是本文的重点。

  • 然后,我们看一下入口的activity
  1.  
  2. public class LauncherActivity extends AppCompatActivity { 
  3.  
  4.     @Override 
  5.     protected void onCreate(Bundle savedInstanceState) { 
  6.         super.onCreate(savedInstanceState); 
  7.         setContentView(R.layout.activity_launcher); 
  8.  
  9.         findViewById(R.id.normal_service_btn).setOnClickListener(v -> { 
  10.             LogUtils.e("普通service 模式"); 
  11.             // todo 
  12.             startActivity(new Intent(get(), NormalActivity.class
  13.                     .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); 
  14.         }); 
  15.         findViewById(R.id.aidl_service).setOnClickListener(v -> { 
  16.             LogUtils.e("AIDL service 模式"); 
  17.             // todo 
  18.         }); 
  19.     } 
  20.  
  21.     public AppCompatActivity get() { 
  22.         return this
  23.     } 
  24. }
public class LauncherActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_launcher); findViewById(R.id.normal_service_btn).setOnClickListener(v -> { LogUtils.e("普通service 模式"); // todo startActivity(new Intent(get(), NormalActivity.class) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); }); findViewById(R.id.aidl_service).setOnClickListener(v -> { LogUtils.e("AIDL service 模式"); // todo }); } public AppCompatActivity get() { return this; }}

依然是简单明了

  • 接下来,我们去看看NormalActivity?不,这个是服务的调用者,我们先去看服务,这样清楚明了一点。
  1.  
  2. public class NormalService extends Service { 
  3.     public NormalService() { 
  4.     } 
  5.  
  6.     @Override 
  7.     public IBinder onBind(Intent intent) { 
  8.         LogUtils.w("normal service bind"); 
  9.         return new LocalBinder(); 
  10.     } 
  11.  
  12.     @Override 
  13.     public boolean onUnbind(Intent intent) { 
  14.         LogUtils.w("normal service unbind"); 
  15.         return super.onUnbind(intent); 
  16.     } 
  17.  
  18.     @Override 
  19.     public void onRebind(Intent intent) { 
  20.         super.onRebind(intent); 
  21.  
  22.         LogUtils.w("normal service rebind"); 
  23.     } 
  24.  
  25.     @Override 
  26.     public void onCreate() { 
  27.         super.onCreate(); 
  28.         LogUtils.w("normal service create"); 
  29.     } 
  30.  
  31.     @Override 
  32.     public int onStartCommand(Intent intent, int flags, int startId) { 
  33.         LogUtils.w("normal service start"); 
  34.         return super.onStartCommand(intent, flags, startId); 
  35.     } 
  36.  
  37.     @Override 
  38.     public void onDestroy() { 
  39.         super.onDestroy(); 
  40.         LogUtils.w("normal service destroy"); 
  41.     } 
  42.  
  43.  
  44.     public class LocalBinder extends Binder { 
  45.         public NormalService get() { 
  46.             return NormalService.this
  47.         } 
  48.     } 
  49.  
  50.     /** 
  51.      * public method invoked by caller 
  52.      * 
  53.      * @return a number of random 
  54.      */ 
  55.     public int getResult() { 
  56.         return new Random().nextInt(500); 
  57.     } 
  58. }
public class NormalService extends Service { public NormalService() { } @Override public IBinder onBind(Intent intent) { LogUtils.w("normal service bind"); return new LocalBinder(); } @Override public boolean onUnbind(Intent intent) { LogUtils.w("normal service unbind"); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { super.onRebind(intent); LogUtils.w("normal service rebind"); } @Override public void onCreate() { super.onCreate(); LogUtils.w("normal service create"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { LogUtils.w("normal service start"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); LogUtils.w("normal service destroy"); } public class LocalBinder extends Binder { public NormalService get() { return NormalService.this; } } /** * public method invoked by caller * * @return a number of random */ public int getResult() { return new Random().nextInt(500); }}

代码略长,不过应该还算是清晰。而且里面没有什么实质性逻辑。最关键的方法就是getResult()。是让调用者调用的。另外,我实现了一个LocalBinder,目的很明确,就是要让调用者可以绑定当前服务。

  • 现在,该去看看该服务的调用者了。
  1. public class NormalActivity extends AppCompatActivity { 
  2.     public boolean bind; 
  3.     private NormalService.LocalBinder mBinder; 
  4.     private ServiceConnection mNormalConn; 
  5.  
  6.     @Override 
  7.     protected void onCreate(Bundle savedInstanceState) { 
  8.         super.onCreate(savedInstanceState); 
  9.         setContentView(R.layout.activity_normal); 
  10.  
  11.         setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); 
  12.         getSupportActionBar().setDisplayHomeAsUpEnabled(true); 
  13.         getSupportActionBar().setTitle("Normal activity"); 
  14.         final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha); 
  15.         upArrow.setColorFilter(getResources().getColor(R.color.colorWhite), PorterDuff.Mode.SRC_ATOP); 
  16.         getSupportActionBar().setHomeAsUpIndicator(upArrow); 
  17.         TextView tvShowResult = (TextView) findViewById(R.id.normal_show_tv); 
  18.         tvShowResult.setText(getString(R.string.show_about_normal_service, "")); 
  19.         Button btnExecute = (Button) findViewById(R.id.normal_ui_btn); 
  20.         btnExecute.setOnClickListener(v -> { 
  21.             LogUtils.w("execute normal service method..."); 
  22.             LogUtils.w("execute normal service method..."); 
  23.             if (bind) { 
  24.                 int result = mBinder.get().getResult(); 
  25.                 LogUtils.e("result=====" + result); 
  26.                 tvShowResult.setText(getString(R.string.show_about_normal_service, result)); 
  27.             } else { 
  28.                 LogUtils.e("bind service fail ,try again......"); 
  29.                 bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); 
  30.                 ToastHelper.show(getApplication(), "bind service fail ,try again......"); 
  31.             } 
  32.         }); 
  33.         mNormalConn = new ServiceConnection() { 
  34.             @Override 
  35.             public void onServiceConnected(ComponentName name, IBinder service) { 
  36.                 bind = true
  37.                 LogUtils.w("normal activity connected normal service..."); 
  38.                 mBinder = (NormalService.LocalBinder) service; 
  39.             } 
  40.  
  41.             @Override 
  42.             public void onServiceDisconnected(ComponentName name) { 
  43.                 bind = false
  44.                 mBinder = null
  45.                 LogUtils.w("normal activity disconnected normal service!"); 
  46.             } 
  47.         }; 
  48.  
  49.         bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); 
  50.     } 
  51.  
  52.     @Override 
  53.     protected void onDestroy() { 
  54.         super.onDestroy(); 
  55.         unbindService(mNormalConn); 
  56.         LogUtils.e("$$$ unbind normal service"); 
  57.     } 
  58.  
  59.     @Override 
  60.     public boolean onOptionsItemSelected(MenuItem item) { 
  61.         if (item.getItemId() == android.R.id.home) { 
  62.             finish(); 
  63.             return true
  64.         } 
  65.         return super.onOptionsItemSelected(item); 
  66.     } 
  67. }
public class NormalActivity extends AppCompatActivity { public boolean bind; private NormalService.LocalBinder mBinder; private ServiceConnection mNormalConn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_normal); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle("Normal activity"); final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha); upArrow.setColorFilter(getResources().getColor(R.color.colorWhite), PorterDuff.Mode.SRC_ATOP); getSupportActionBar().setHomeAsUpIndicator(upArrow); TextView tvShowResult = (TextView) findViewById(R.id.normal_show_tv); tvShowResult.setText(getString(R.string.show_about_normal_service, "")); Button btnExecute = (Button) findViewById(R.id.normal_ui_btn); btnExecute.setOnClickListener(v -> { LogUtils.w("execute normal service method..."); LogUtils.w("execute normal service method..."); if (bind) { int result = mBinder.get().getResult(); LogUtils.e("result=====" + result); tvShowResult.setText(getString(R.string.show_about_normal_service, result)); } else { LogUtils.e("bind service fail ,try again......"); bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); ToastHelper.show(getApplication(), "bind service fail ,try again......"); } }); mNormalConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bind = true; LogUtils.w("normal activity connected normal service..."); mBinder = (NormalService.LocalBinder) service; } @Override public void onServiceDisconnected(ComponentName name) { bind = false; mBinder = null; LogUtils.w("normal activity disconnected normal service!"); } }; bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mNormalConn); LogUtils.e("$$$ unbind normal service"); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { finish(); return true; } return super.onOptionsItemSelected(item); }}

代码略长,因为里面还做了除了调用服务之外的其他操作。关键代码看 20~50 ,这30行的代码即可。这个代码也不用解释了,就是在界面上有一个按钮,每次点击按钮都会调用服务里面的方法得到一个随机数,并显示在textview上面罢了。至于怎么去绑定服务,我相信大家都很娴熟了,不必再解释了。

不过我觉得值得注意的是38行的代码mBinder = (NormalService.LocalBinder) service;,也就是我们通过类型强转得到一个我们自己定义的IBinder对象,也只有得到它,才能得到服务的对象,然后调用服务里面的方法。

  • ok,代码结束了,一个最简单的bindService完成了。运行截图就不贴了,没意义,大家都知道是什么样子的。

.........................

现在,去实现最简单的aidl,也就是基于当前代码的一些修改。

那么,要怎么修改呢? 首先,我们给service设置一个单独的进程,修改清单文件,在service节点里面添加一个属性android:process=":normal".这样就让service和'activity'之间跨进程了。 然后,我们什么也不做,直接运行代码。注意:我们所做的修改仅仅是给service设置了一个单独的进程,java代码没有改动一行。

现在运行之后,是什么样子的效果呢?程序崩溃了。看日志:

  1. FATAL EXCEPTION: main 
  2.   Process: com.pythoncat.ipcorservice, PID: 2811 
  3.   java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.pythoncat.ipcorservice.service.NormalService$LocalBinder 
  4.       at com.pythoncat.ipcorservice.activity.NormalActivity$1.onServiceConnected(NormalActivity.java:58
  5.       at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1256
  6.       at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1273
  7.       at android.os.Handler.handleCallback(Handler.java:815
  8.       at android.os.Handler.dispatchMessage(Handler.java:104
  9.       at android.os.Looper.loop(Looper.java:194
  10.       at android.app.ActivityThread.main(ActivityThread.java:5667
  11.       at java.lang.reflect.Method.invoke(Native Method) 
  12.       at java.lang.reflect.Method.invoke(Method.java:372
  13.       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:962
  14.       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
FATAL EXCEPTION: main Process: com.pythoncat.ipcorservice, PID: 2811 java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.pythoncat.ipcorservice.service.NormalService$LocalBinder at com.pythoncat.ipcorservice.activity.NormalActivity$1.onServiceConnected(NormalActivity.java:58) at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1256) at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1273) at android.os.Handler.handleCallback(Handler.java:815) at android.os.Handler.dispatchMessage(Handler.java:104) at android.os.Looper.loop(Looper.java:194) at android.app.ActivityThread.main(ActivityThread.java:5667) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:962) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

真正有用的日志就一行

  1. java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.pythoncat.ipcorservice.service.NormalService$LocalBinder`.
java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.pythoncat.ipcorservice.service.NormalService$LocalBinder`.

看了日志我们大概明白了,我们拿到的Ibinder对象,并不是我们在service中定义的NormalService$LocalBinder对象。

那么,为什么会这样呢?简单的理解就是,每个进程的内存是独立的,在A进程开辟的内存,B进程并不能访问。如何解决? 我并不知道怎么解决。看大神们的博客大概就是说,通过IBinder所在的共享内存区域进行数据交换,实现跨进程通信,实现起来也就是aidl.

  • 关于这方面的理论知识,我也不多介绍了,无论是android官方文档,还是一些大神的博客,都对此有比较清晰的介绍。我就简单说一下实现方式。

既然当前activityservice不在同一个进程了,无法通过之前的方式直接拿到IBinder对象,那么,我们就定义一个.aidl来实现之间的通信。

从上面的代码上看,我们实际上是希望调用service中的getResult()方法。那么,我们就定义一个.aidl里面包含该方法即可。

  • 1.如何操作?右键appmodule --> new --> AIDL -->AIDL File .然后写一个文件名如:NormalBinder,然后直接回车。在里面添加需要调用的service中的方法。
  1. interface NormalBinder { 
  2.     /** 
  3.      * Demonstrates some basic types that you can use as parameters 
  4.      * and return values in AIDL. 
  5.      */ 
  6.     void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, 
  7.             double aDouble, String aString); 
  8.     int getResult(); 
  9. }
interface NormalBinder { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); int getResult();}
  • 2.接下来,rebuild一下项目。会自动生成一些Java文件。至于生成的是什么,在哪里,这里也不说明了,跟主题无关。
  • 3.然后,在service中去实现一个可用于aidlIBinder.
  1. public class RemoteBinder extends NormalBinder.Stub { 
  2.  
  3.         @Override 
  4.         public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { 
  5.  
  6.         } 
  7.  
  8.         @Override 
  9.         public int getResult() throws RemoteException { 
  10.             return new Random().nextInt(500); 
  11.         } 
  12.     }
public class RemoteBinder extends NormalBinder.Stub { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public int getResult() throws RemoteException { return new Random().nextInt(500); } }

修改之后的service长这样子:

  1.  
  2. public class NormalService extends Service { 
  3.     public NormalService() { 
  4.     } 
  5.  
  6.     @Override 
  7.     public IBinder onBind(Intent intent) { 
  8.         LogUtils.w("normal service bind"); 
  9. //        return new LocalBinder(); 
  10.         return new RemoteBinder(); 
  11.     } 
  12.  
  13.     @Override 
  14.     public boolean onUnbind(Intent intent) { 
  15.         LogUtils.w("normal service unbind"); 
  16.         return super.onUnbind(intent); 
  17.     } 
  18.  
  19.     @Override 
  20.     public void onRebind(Intent intent) { 
  21.         super.onRebind(intent); 
  22.  
  23.         LogUtils.w("normal service rebind"); 
  24.     } 
  25.  
  26.     @Override 
  27.     public void onCreate() { 
  28.         super.onCreate(); 
  29.         LogUtils.w("normal service create"); 
  30.     } 
  31.  
  32.     @Override 
  33.     public int onStartCommand(Intent intent, int flags, int startId) { 
  34.         LogUtils.w("normal service start"); 
  35.         return super.onStartCommand(intent, flags, startId); 
  36.     } 
  37.  
  38.     @Override 
  39.     public void onDestroy() { 
  40.         super.onDestroy(); 
  41.         LogUtils.w("normal service destroy"); 
  42.     } 
  43.  
  44.  
  45.     public class LocalBinder extends Binder { 
  46.         public NormalService get() { 
  47.             return NormalService.this
  48.         } 
  49.     } 
  50.  
  51.     /** 
  52.      * public method invoked by caller 
  53.      * 
  54.      * @return a number of random 
  55.      */ 
  56.     public int getResult() { 
  57.         return new Random().nextInt(500); 
  58.     } 
  59.  
  60.     public class RemoteBinder extends NormalBinder.Stub { 
  61.  
  62.         @Override 
  63.         public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { 
  64.  
  65.         } 
  66.  
  67.         @Override 
  68.         public int getResult() throws RemoteException { 
  69.             return new Random().nextInt(500); 
  70.         } 
  71.     } 
  72. }
public class NormalService extends Service { public NormalService() { } @Override public IBinder onBind(Intent intent) { LogUtils.w("normal service bind");// return new LocalBinder(); return new RemoteBinder(); } @Override public boolean onUnbind(Intent intent) { LogUtils.w("normal service unbind"); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { super.onRebind(intent); LogUtils.w("normal service rebind"); } @Override public void onCreate() { super.onCreate(); LogUtils.w("normal service create"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { LogUtils.w("normal service start"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); LogUtils.w("normal service destroy"); } public class LocalBinder extends Binder { public NormalService get() { return NormalService.this; } } /** * public method invoked by caller * * @return a number of random */ public int getResult() { return new Random().nextInt(500); } public class RemoteBinder extends NormalBinder.Stub { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public int getResult() throws RemoteException { return new Random().nextInt(500); } }}
  • 4.然后需要修改调用的activity了。

得将之前的IBinder对象换成可以aidlIBinder了。

  1. mNormalConn = new ServiceConnection() { 
  2.     @Override 
  3.     public void onServiceConnected(ComponentName name, IBinder service) { 
  4.         bind = true
  5.         LogUtils.w("normal activity connected normal service..."); 
  6. //                mBinder = (NormalService.LocalBinder) service; 
  7.         mBinder = NormalBinder.Stub.asInterface(service); 
  8.     } 
  9.  
  10.     @Override 
  11.     public void onServiceDisconnected(ComponentName name) { 
  12.         bind = false
  13.         mBinder = null
  14.         LogUtils.w("normal activity disconnected normal service!"); 
  15.     } 
  16. };
mNormalConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bind = true; LogUtils.w("normal activity connected normal service...");// mBinder = (NormalService.LocalBinder) service; mBinder = NormalBinder.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { bind = false; mBinder = null; LogUtils.w("normal activity disconnected normal service!"); }};

发现什么改变了没有,就是将第6行替换成第7行。也就是mbinder的获取方式改变了,得到的对象也不是之前的对象了。

完全替换之后的activity长这样子的

  1. public class NormalActivity extends AppCompatActivity { 
  2.     public boolean bind; 
  3.     private ServiceConnection mNormalConn; 
  4.     private NormalBinder mBinder; 
  5.  
  6.     @Override 
  7.     protected void onCreate(Bundle savedInstanceState) { 
  8.         super.onCreate(savedInstanceState); 
  9.         setContentView(R.layout.activity_normal); 
  10.  
  11.         setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); 
  12.         getSupportActionBar().setDisplayHomeAsUpEnabled(true); 
  13.         getSupportActionBar().setTitle("Normal activity"); 
  14.         final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha); 
  15.         upArrow.setColorFilter(getResources().getColor(R.color.colorWhite), PorterDuff.Mode.SRC_ATOP); 
  16.         getSupportActionBar().setHomeAsUpIndicator(upArrow); 
  17.         TextView tvShowResult = (TextView) findViewById(R.id.normal_show_tv); 
  18.         tvShowResult.setText(getString(R.string.show_about_normal_service, "")); 
  19.         Button btnExecute = (Button) findViewById(R.id.normal_ui_btn); 
  20.         btnExecute.setOnClickListener(v -> { 
  21.             LogUtils.w("execute normal service method..."); 
  22.             LogUtils.w("execute normal service method..."); 
  23.             if (bind) { 
  24. //                int result = mBinder.get().getResult(); 
  25.                 int result = 0
  26.                 try { 
  27.                     result = mBinder.getResult(); 
  28.                 } catch (RemoteException e) { 
  29.                     e.printStackTrace(); 
  30.                 } 
  31.                 LogUtils.e("result=====" + result); 
  32.                 tvShowResult.setText(getString(R.string.show_about_normal_service, result)); 
  33.             } else { 
  34.                 LogUtils.e("bind service fail ,try again......"); 
  35.                 bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); 
  36.                 ToastHelper.show(getApplication(), "bind service fail ,try again......"); 
  37.             } 
  38.         }); 
  39.         mNormalConn = new ServiceConnection() { 
  40.             @Override 
  41.             public void onServiceConnected(ComponentName name, IBinder service) { 
  42.                 bind = true
  43.                 LogUtils.w("normal activity connected normal service..."); 
  44. //                mBinder = (NormalService.LocalBinder) service; 
  45.                 mBinder = NormalBinder.Stub.asInterface(service); 
  46.             } 
  47.  
  48.             @Override 
  49.             public void onServiceDisconnected(ComponentName name) { 
  50.                 bind = false
  51.                 mBinder = null
  52.                 LogUtils.w("normal activity disconnected normal service!"); 
  53.             } 
  54.         }; 
  55.  
  56.         bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); 
  57.     } 
  58.  
  59.     @Override 
  60.     protected void onDestroy() { 
  61.         super.onDestroy(); 
  62.         unbindService(mNormalConn); 
  63.         LogUtils.e("$$$ unbind normal service"); 
  64.     } 
  65.  
  66.     @Override 
  67.     public boolean onOptionsItemSelected(MenuItem item) { 
  68.         if (item.getItemId() == android.R.id.home) { 
  69.             finish(); 
  70.             return true
  71.         } 
  72.         return super.onOptionsItemSelected(item); 
  73.     } 
  74. }
public class NormalActivity extends AppCompatActivity { public boolean bind; private ServiceConnection mNormalConn; private NormalBinder mBinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_normal); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle("Normal activity"); final Drawable upArrow = getResources().getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha); upArrow.setColorFilter(getResources().getColor(R.color.colorWhite), PorterDuff.Mode.SRC_ATOP); getSupportActionBar().setHomeAsUpIndicator(upArrow); TextView tvShowResult = (TextView) findViewById(R.id.normal_show_tv); tvShowResult.setText(getString(R.string.show_about_normal_service, "")); Button btnExecute = (Button) findViewById(R.id.normal_ui_btn); btnExecute.setOnClickListener(v -> { LogUtils.w("execute normal service method..."); LogUtils.w("execute normal service method..."); if (bind) {// int result = mBinder.get().getResult(); int result = 0; try { result = mBinder.getResult(); } catch (RemoteException e) { e.printStackTrace(); } LogUtils.e("result=====" + result); tvShowResult.setText(getString(R.string.show_about_normal_service, result)); } else { LogUtils.e("bind service fail ,try again......"); bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); ToastHelper.show(getApplication(), "bind service fail ,try again......"); } }); mNormalConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bind = true; LogUtils.w("normal activity connected normal service...");// mBinder = (NormalService.LocalBinder) service; mBinder = NormalBinder.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { bind = false; mBinder = null; LogUtils.w("normal activity disconnected normal service!"); } }; bindService(new Intent(this, NormalService.class), mNormalConn, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mNormalConn); LogUtils.e("$$$ unbind normal service"); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { finish(); return true; } return super.onOptionsItemSelected(item); }}
  • 现在,一个最简单的aidl就完成了。现在运行代码,和之前的效果完全一样。还是每点击一次按钮,就会在textview上显示一个500以内的随机数。不过,现在是跨进程调用了,不再是同一个进程了。为什么说是跨进程?你可以尝试分别输出service所在的pidactivity所在的pid就一目了然了。

    • int pid = Process.myPid();,可以使用这句代码完成当前pid的获取。

吐槽下 amd 的cpu,超级辣鸡!android studio 能卡死,即使是16G内存,2G独显,120G的固态。

结语

  • 相信通过这长篇的说明,大家知道怎么去写一个最简单的aidl了。我想,通过这个记录,我应该也会对实现最简单的一个aidl更加熟练一点。
  • 但是,我们知道aidl的使用场景往往是多module之间,多app之间。而且进行数据的交互可能是相互的,不仅仅是一方输出,一方接收。而是双方都能输出,双方都能够接收。而且传输的数据也不仅仅是基本类型的数据,可能是一个pojo类型的数据。
  • 没有关系,这只是一个开始。目的是抛砖引玉。
  • 后续,我也会不定期更新这方面的知识。

最后,关于我:野生安卓猿一只,入安卓坑已有几年,一直徘徊在新手和菜鸟之间。

0 0
原创粉丝点击