android 跨应用启动/绑定Service && aidl
以前写了一篇文章是关于同一个应用中有一个Activity 和 一个 Service,然后在AndroidManifest.xml文件中 将service的 android:process设置为":remote" , 这里要强调一下带“:”和不带“:”时的属性, android:process=":remote",代表在应用 程序里,当需要该service时,会自动创建新的进程,意思就是说你配的service会在另外一个进程中运行,而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。上次虽然同一个应用中实现了Activity和Service的夸进程通信,但是感觉不爽,毕竟是在同一应用中,这次实现一个两个应用中的跨进程使用aidl通信。1 首先在创建一个应用工程MyApplication4,作用就是创建一个继承自Service的一个服务类,然后再创建一个aidl 文件。Myservice.java
package com.example.lsw.myapplication;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { Log.d(MainActivity.TAG,"onBind"); // TODO: Return the communication channel to the service. return new MyBinder(); } @Override public void onCreate() { Log.d(MainActivity.TAG,"onCreate"); super.onCreate(); } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(MainActivity.TAG,"onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.d(MainActivity.TAG,"onDestroy"); super.onDestroy(); } public class MyBinder extends IMyAidlInterface.Stub{ @Override public String getMusicName() throws RemoteException { return "明天会更好"; } }}
这里也强调一个知识点,启动Service一共有两种方法,一个是StartService,这种启动方式一般启动的Service和当前启动它的组件就没有任何关系了,和这个组件处于不同的进程了。 另一种启动方式就是bindService这种方法,这种启动方式Service和绑定它的组件共存亡。(具体情况大家可以去查看service的启动方式)。
IMyAidlInterface.aidl
// IMyAidlInterface.aidlpackage com.example.lsw.myapplication;// Declare any non-default types here with import statementsinterface IMyAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ String getMusicName();}
这里就是定义一个接口,在MyService中定义一个class 去继承这个接口然后,实现这个接口的方法,之后再通过onBind()方法将这个继承接口类的对象返回给绑定的应用中,实现可以访问到MyService内部方法的机制。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
这里强调一下属性 android:exported="true"表示这个进程中的MyService服务允许外接访问。
可以看到这了的aidl包名为 com/example/lsw/myapplication
2 Client 端
(1) 重新创建一个应用工程MyApplication5,主要任务就是在Mainactivity.java中点击button1去绑定MyApplication4中的MyService,然后点击button2调用 aidl中的getMusicName()方法。
Mainctivity.java
package com.example.lisiwei.myapplication;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;import com.example.lsw.myapplication.IMyAidlInterface;public class MainActivity extends AppCompatActivity { private Button m_startButton = null; private Button m_getMusicButton = null; private ServiceConnection m_serviceConnection = null; private IMyAidlInterface m_iMyAidlInterface = null; private Context m_context = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { m_context = this; m_startButton = findViewById(R.id.startButton); m_getMusicButton = findViewById(R.id.getMusicButton); m_serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d("lisiwei","onServiceConnected"); if (null == m_iMyAidlInterface) { m_iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } } @Override public void onServiceDisconnected(ComponentName name) { } }; m_startButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("lisiwei","m_startButton setOnClickListener"); Intent intent = new Intent(); // 这里注意这两个参数第一个是Myservice的包名也就是application4的包名,第二个是包名+类型, intent.setComponent(new ComponentName("com.example.lsw.myapplication","com.example.lsw.myapplication.MyService")); bindService(intent,m_serviceConnection,Context.BIND_AUTO_CREATE); } }); m_getMusicButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("lisiwei","m_getMusicButton setOnClickListener + " + getMusicName()); Toast.makeText(m_context,getMusicName(),Toast.LENGTH_LONG).show(); } }); } private String getMusicName() { String name = null; if ( null != m_iMyAidlInterface) { try { name = m_iMyAidlInterface.getMusicName(); } catch (RemoteException e) { e.printStackTrace(); } } return name; }}
这里需要强调4个点:
1 因为我们需要去绑定application4中的service就涉及到了Intent启动service,自从Android 5.0之后就不允许隐式启动intent 启动service了,只能显示intent启动service。
2 就是比较坑的一个地方,这里感谢同事的指导,就是要将application4中的aidl文件copy到application5中,而且两个应用中的aidl要处于同一个目录下。
3 这个又是一个坑逼的地方,我要通过application5(client)去绑定application4中service,结果必须要先启动application4的工程,注意这里只是启动了工程,并没有启动application4中的service,service还是由application5中点击button来绑定。你可以看log,是点击button之后application4中的service还是第一次走onCreate方法,那就证明application4只是启动了它自身的工程,并没有启动服务,服务还是由application5绑定之后启动的。
4 为什么不在application5中启动Myservice的时候又通过m_iMyAidlInterface去调用getMusicName()方法那?因为绑定是一个异步执行的过程,如果绑定之后立马去使用m_iMyAidlInterface这个时候m_iMyAidlInterface还可能是null。
这里这个项目的路径名和application4不一样,但是aidl的路径名一样 都为com/example/lsw/myapplication
具体代码路径: https://download.csdn.net/download/lisiwei1994/10946447
更多相关文章
- android 使用AsyncTask实现异步下载文件
- android通过更改hosts免优酷广告方法
- 如何优雅的避免android(安卓)运行时崩溃
- android 热修复之类加载机制
- Android进阶(一)View体系
- [android] HttpURLConnection的初步学习
- 深入了解Android(安卓)任务和进程
- Android(安卓)应用初始化及窗体事件的分发
- Android(安卓)三言两语