跨进程之不通应用之间
1在app中启动另外一个app
A应用拉起B应用的非主页面的某个页面,并且传值(一般是鉴权token值、type值以及其他参数值,本文仅仅以传递type值为例),B应用根据传递过来的不同的值启动不同的页面。需要注意的是A应用拉起B应用的启动页(SplashActivity)并传值(token值和type值以及其他参数值),在启动页获取到值并且存储到SharedPreferences中,最好再存储一个Boolean值,代表这是从第三方应用拉起来的。然后有两种情况,通过Activity的管理工具类判断栈中是否含有B应用的主页面(即B应用是否已经运行在后台)①不含有:代表后台并没有运行B应用,那么我们正常启动主页面,在主页(MainActivity)从SharedPreferences中获取到这个Boolean值与A应用传递过来的值,由主页根据A应用传递过来的值打开相应的页面,这样用户点击返回顺序为:B应用相应页面-B应用主页面-A应用;②含有:代表B应用已经运行在后台,并且现在可能停留在某个页面,此时,我们不应该在启动页继续走启动主页面的逻辑了,如果继续启动主页面,由于我们设置了主页的启动模式为android:launchMode=”singleTask”,那么B应用栈中主页面以上页面都会出栈,用户将看不到刚刚浏览过的页面,这样太不友好了。因此此时的解决方案是我们要在启动页发个静态广播,在广播接收者中获取到SharedPreferences中的Boolean值与A应用传递过来的值,并且通过Activity的管理工具类获取到栈顶的Activity,然后在栈顶Activity的基础上启动相应的页面,(当然,这里也可以不发送广播,直接在启动页通过Activity的管理工具类获取到栈顶的Activity,然后在栈顶Activity的基础上启动相应的页面,这样效果是一样的)这样用户点击返回的顺序为:B应用相应页面-B应用用户拉起客户端之前浏览的页面-B应用主页面-A应用。
b应用启动页清单文件配置
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!--ACTION启动配置用于隐士启动app host path选填-->
<intent-filter>
<data
android:host="pull.csd.demo"
android:path="/cyn"
android:scheme="csd" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
A应用启动B的代码
Intent intent = new Intent();
intent.setData(Uri.parse("csd://pull.csd.demo/cyn?type=110"));
intent.putExtra("", "");//这里Intent当然也可传递参数,但是一般情况下都会放到上面的URL中进行传递
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
B应用获取A传递的信息
if(null!=intent&&null!=intent.data) {
val uri:Uri = intent.data
if (uri != null) {
Toast.makeText(this,uri.scheme + "--" + uri.host + "--" + uri.path + uri.getQueryParameter("type"),Toast.LENGTH_SHORT).show()
}
}
2广播
public class BroadcastActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
View send = findViewById(R.id.send_broad_cast);
send.setOnClickListener(v->{
Intent intent=new Intent();
intent.setAction("test_send_cast");
intent.putExtra("info", "传递内容");
sendBroadcast(intent);
System.out.println("发送了广播");
});
}
另外一个项目中接受广播
package com.example.shanghai.daojishiapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
public class ReceiveBroadcastActivity extends AppCompatActivity {
BroadcastReceiver broadcastReceiver;
IntentFilter intentFilter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_receive_broadcast);
intentFilter=new IntentFilter();
intentFilter.addAction("test_send_cast");
broadcastReceiver=new MyReceiver();
registerReceiver(broadcastReceiver,intentFilter);
}
class MyReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(intent!=null){
if(!TextUtils.isEmpty(intent.getAction())){
System.out.println("!TextUtils.isEmpty(intent.getAction()");
}
if(!TextUtils.isEmpty(intent.getStringExtra("info"))){
System.out.println(intent.getStringExtra("info"));
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
}
3AIDL (Android interface definition language)
在AndroidStudio 中新建aidl文件
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* 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);
boolean forwardPayMoney(float money);
}
新建一个service隐士启动
<service
android:name=".service.ProvideService"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="com.example.shanghai.daojishiapplication.action.AIDL"></action>
</intent-filter>
</service>
package com.example.shanghai.daojishiapplication.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import com.example.shanghai.daojishiapplication.IMyAidlInterface;
/**
* Created by shanghai on 2018/4/10.
*/
public class ProvideService extends Service{
private static final String TAG="ProvideService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println(TAG+"onBind");
return new MyBinder();
}
private class MyBinder extends IMyAidlInterface.Stub{
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public boolean forwardPayMoney(float money) throws RemoteException {
System.out.println(TAG+"public boolean forwardPayMoney(float money) throws RemoteException");
return false;
}
}
}
把main目录下的aidl包拷贝到在另外一个app中的main目录下build项目
在activity中bindservice调用service中的方法
package com.github.zackratos.rvitemam;
import android.content.ComponentName;
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.view.View;
import com.example.shanghai.daojishiapplication.IMyAidlInterface;
public class TestAidlActivity extends AppCompatActivity {
private View btn_bind;
private View btn_invoke;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_aidl);
btn_bind = findViewById(R.id.btn_bind);
btn_invoke = findViewById(R.id.btn_invoke);
btn_bind.setOnClickListener(v->{
System.out.println("TestAidlActivity--btn_bind");
bindservice();
});
btn_invoke.setOnClickListener(v -> {
System.out.println("TestAidlActivity--btn_invoke");
try {
boolean b = mIService.forwardPayMoney(0.1f);
System.out.println("TestAidlActivity-forwarpay="+b);
} catch (RemoteException e) {
e.printStackTrace();
}
});
}
/**
* 绑定远程服务
*/
public void bindservice() {
Intent mIntent = new Intent();
mIntent.setAction("com.example.shanghai.daojishiapplication.action.AIDL");
mIntent.setPackage("com.example.shanghai.daojishiapplication");//需要指定提供服务的程序包名
MyConnection myConnection = new MyConnection();
bindService(mIntent, myConnection,BIND_AUTO_CREATE);
}
private IMyAidlInterface mIService;
class MyConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIService = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
4Messenger
不需要创建aidl文件
service隐士启动
<service
android:name=".service.MyService"
android:enabled="true"
android:exported="true"
android:process=":remote">
<intent-filter>
<action android:name="com.example.shanghai.daojishiapplication.service.MyService"></action>
</intent-filter>
</service>
package com.example.shanghai.daojishiapplication.service;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.INotificationSideChannel;
import android.util.Log;
/**
* 与客户端跨进程通信
*/
public class MyService extends Service {
/** Command to the service to display a message */
public static final int MSG_SAY_HELLO = 1;
private static final String TAG ="wzj" ;
/* 用于接收从客户端传递过来的数据 */
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
System.out.println("thanks,Service had receiver message from client!");
Messenger client=msg.replyTo;
Message replyMsg=Message.obtain(null,MyService.MSG_SAY_HELLO);
Bundle bundle=new Bundle();
bundle.putString("reply","ok~,I had receiver message from you! ");
replyMsg.setData(bundle);
try {
client.send(replyMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
/* 创建Messenger并传入Handler实例对象 */
final Messenger mMessenger = new Messenger(new IncomingHandler());
/* 当绑定Service时,该方法被调用,将通过mMessenger返回一个实现IBinder接口的实例对象 */
@Override
public IBinder onBind(Intent intent) {
System.out.println("Service is invoke onBind");
return mMessenger.getBinder();
}
}
activity
package com.github.zackratos.rvitemam;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MessageActivity extends AppCompatActivity {
/* 与服务端交互的Messenger */
Messenger mService = null;
/**
* Flag indicating whether we have called bind on the service.
*/
boolean mBound;
private View btn;
private StringBuffer printMessage = new StringBuffer();
private View send;
private View unbind;
private String SERVICE_ACTION="com.example.shanghai.daojishiapplication.service.MyService";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message);
btn = findViewById(R.id.btn_bind);
send = findViewById(R.id.btn_send);
unbind = findViewById(R.id.btn_unbind);
btn.setOnClickListener(v -> {
System.out.println("onClick-->bindService");
Intent mIntent = new Intent();
mIntent.setAction("com.example.shanghai.daojishiapplication.service.MyService");
mIntent.setPackage("com.example.shanghai.daojishiapplication");//需要指定提供服务的程序包名
bindService(mIntent, mConnection,BIND_AUTO_CREATE);
});
send.setOnClickListener(v -> {
System.out.println("click"+"sayHello");
sayHello();
});
unbind.setOnClickListener(v -> {
if (mBound) {
System.out.println("onClick-->unbindService");
unbindService(mConnection);
mBound = false;
}
});
}
/* 实现与服务端链接的对象ServiceConnection */
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
System.out.println("onServiceConnected");
/* 通过服务端传递的IBinder对象,创建相应的Messenger
* 通过该Messenger对象与服务端进行交互 */
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello() {
if (!mBound) return;
System.out.println("sayHello");
// 创建与服务交互的消息实体Message
Message msg = Message.obtain();
msg.what=1;
msg.replyTo=mRecevierReplyMsg;
try {
//发送消息
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private static class ReceiverReplyMsgHandler extends Handler {
private static final String TAG = "zj";
@Override
public void handleMessage(Message msg) {
System.out.println("receiver message from service:");
switch (msg.what) {
//接收服务端回复
case 1:
System.out.println("receiver message from service:" + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
private Messenger mRecevierReplyMsg = new Messenger(new ReceiverReplyMsgHandler());
}
2跨进程通信之与service之间
(首先讲一下两种启动方式,Service以及service与activity交互)
startService():
1、启动服务对象多次启动同时只会产生一个,onCreate()方法只会在Service第一次被创建的时候调用,多次点击启动会执行多次onStartCommand()方法,onDestroy()方法只会在Service第一次被停止的时候调用,多次点击停止不会报异常,也不再执行onDestroy()方法。
2、一旦启动,Service将一直运行在后台(run in the background indefinitely)即便启动Service的组件已被destroy。
3、停止一个started服务有两种方法:
(1)在外部使用stopService()手动停止。
(2)在服务内部(onStartCommand方法内部)使用stopSelf()方法,使服务执行完毕后自动停止。比如说,一个start的Service执行在后台下载或上传一个文件的操作,完成之后,Service应自己停止。
bindService()
仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。(通过 unbindService()方法来关闭这种连接)
service与activity交互
(1)startService可以通过intent传递
(2)bindservice()如果我们的服务仅供本地应用使用,不需要跨进程工作,则可以实现自有 Binder 类,让客户端通过该类直接访问服务中的公共方法。其使用开发步骤如下
创建BindService服务端,继承自Service并在类中,创建一个实现IBinder 接口的实例对象并提供公共方法给客户端调用
从 onBind() 回调方法返回此 Binder 实例。
在客户端中,从 onServiceConnected() 回调方法接收 Binder,并使用提供的方法调用绑定服务。
注意:此方式只有在客户端和服务位于同一应用和进程内才有效,如对于需要将 Activity 绑定到在后台播放音乐的自有服务的音乐应用,此方式非常有效。另一点之所以要求服务和客户端必须在同一应用内,是为了便于客户端转换返回的对象和正确调用其 API。服务和客户端还必须在同一进程内,因为此方式不执行任何跨进程编组
(3)同一个进程eventbus也可
(4)service在独立的进程中采用Messenger进行传递,或者aidl下面讲一下Messenger的使用方法,aidl放在后面跨进程通信中讲解
package com.example.shanghai.daojishiapplication.service;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.INotificationSideChannel;
import android.util.Log;
/**
* 与客户端跨进程通信
*/
public class MyService extends Service {
/** Command to the service to display a message */
public static final int MSG_SAY_HELLO = 1;
private static final String TAG ="wzj" ;
/* 用于接收从客户端传递过来的数据 */
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
System.out.println("thanks,Service had receiver message from client!");
Messenger client=msg.replyTo;
Message replyMsg=Message.obtain(null,MyService.MSG_SAY_HELLO);
Bundle bundle=new Bundle();
bundle.putString("reply","ok~,I had receiver message from you! ");
replyMsg.setData(bundle);
try {
client.send(replyMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
/* 创建Messenger并传入Handler实例对象 */
final Messenger mMessenger = new Messenger(new IncomingHandler());
/* 当绑定Service时,该方法被调用,将通过mMessenger返回一个实现IBinder接口的实例对象 */
@Override
public IBinder onBind(Intent intent) {
System.out.println("Service is invoke onBind");
return mMessenger.getBinder();
}
}
package com.example.shanghai.daojishiapplication;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.example.shanghai.daojishiapplication.service.MyService;
public class MessageActivity extends AppCompatActivity {
/* 与服务端交互的Messenger */
Messenger mService = null;
/**
* Flag indicating whether we have called bind on the service.
*/
boolean mBound;
private View btn;
private StringBuffer printMessage = new StringBuffer();
private View send;
private View unbind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message);
btn = findViewById(R.id.btn_bind);
send = findViewById(R.id.btn_send);
unbind = findViewById(R.id.btn_unbind);
btn.setOnClickListener(v -> {
System.out.println("onClick-->bindService");
//当前Activity绑定服务端
bindService(new Intent(MessageActivity.this, MyService.class), mConnection,
Context.BIND_AUTO_CREATE);
});
send.setOnClickListener(v -> {
sayHello();
});
unbind.setOnClickListener(v -> {
if (mBound) {
System.out.println("onClick-->unbindService");
unbindService(mConnection);
mBound = false;
}
});
}
/* 实现与服务端链接的对象ServiceConnection */
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
/* 通过服务端传递的IBinder对象,创建相应的Messenger
* 通过该Messenger对象与服务端进行交互 */
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello() {
if (!mBound) return;
System.out.println("sayHello");
// 创建与服务交互的消息实体Message
Message msg = Message.obtain(null, MyService.MSG_SAY_HELLO, 0, 0);
msg.replyTo=mRecevierReplyMsg;
try {
//发送消息
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private static class ReceiverReplyMsgHandler extends Handler {
private static final String TAG = "zj";
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//接收服务端回复
case MyService.MSG_SAY_HELLO:
System.out.println("receiver message from service:" + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
private Messenger mRecevierReplyMsg = new Messenger(new ReceiverReplyMsgHandler());
}
清单文件中配置
<service
android:name=".service.MyService"
android:enabled="true"
android:exported="true"
android:process=":remote" />
intentservice解决servcie不能执行耗时操作这一问题,service保活可以
将service设置为前台服务,或者设置两个服务相互监听,在ondestory中发送广播
在另外一个服务中接收到广播再start服务
关于service更多使用方法信息参考(https://www.jianshu.com/p/086869a2f0ac)
网友评论