进程
上次说到了线程和多线程之间的通信方式,这次我们学习多进程。
Android每个程序的运行都会自动创建一个进程,进程名会以包名命名。进程是系统进行资源分配和调度的基本单位,形象的来说就是,一个车间就是一个进程,一个进程中可以有多个线程,一个车间可以有多个生产线。
进程的创建
<service android:name=".Messenger_Service"
android:process="com.example.lenovo_pc.class_eight_messnger">
</service>
只需加android:process=”value”就可以创建一个新的进程,所在进程的名字就是value值,如果android:process的value不是”:”开头,则系统里有同样名字的进程的话,会放到已存在的同名进程里运行,这样能减小消耗。如果android:process的value是以”:”开头,则启动一个名字为value的进程。
同样,activity,Broadcast等开启新的进程也是使用相同的方法。
进程的生命周期
共分五个等级
- 前台进程 (重要性最高)
- 可见进程
- 服务进程
- 后台进程
- 空进程 (重要性最低)
其中,拥有最低重要性的进程会首先被干掉,然后就是那些次低重要性的进程,依次类推。
多进程
我们都知道,android平台对应用都有内存限制,使用多进程就可以使得我们一个apk所使用的内存限制加大几倍,从而使我们的程序处理起来更加流畅。而且由于进程之间内存不共享,更加稳定安全,不易崩溃。
多进程之间的通信
由于进程之间数据不共享,所以就要使用多进程之间的通信。
- Messenger+Handler 适用于:多进程,单线程
- Aidl 适用于多进程,多线程
Messenger
Google定义:This allows for the implementation of message-based communication across processes
允许实现基于消息的进程间通信的方式。
至于什么是基于消息的进程间通信方式,大家可以参考:
http://blog.csdn.net/lmj623565791/article/details/47017485
一般的使用方法:
一般使用方法如下:
1。远程通过
mMessenger = new Messenger(mHandler)
创建一个信使对象
2。客户端使用bindlerService请求连接远程
3。远程onBind方法返回一个bindler
return mMessenger.getBinder();
4.客户端使用远程返回的bindler得到一个信使(即得到远程信使)
public void onServiceConnected(ComponentName name, IBinder service) {
rMessenger = new Messenger(service);
……
}
这里虽然是new了一个Messenger,但我们查看它的实现
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
发现它的mTarget是通过Aidl得到的,实际上就是远程创建的那个。
5。客户端可以使用这个远程信使对象向远程发送消息:rMessenger.send(msg);
这样远程服务端的Handler对象就能收到消息了,然后可以在其handlerMessage(Message msg)方法中进行处理。(该Handler对象就是第一步服务端创建Messenger时使用的参数mHandler).
经过这5个步骤貌似只有客户端向服务端发送消息,这样的消息传递是单向的,那么如何实现双向传递呢?
首先需要在第5步稍加修改,在send(msg)前通过msm.replyTo = mMessenger将自己的信使设置到消息中,这样服务端接收到消息时同时也得到了客户端的信使对象了,然后服务端可以通过/得到客户端的信使对象,并向它发送消息 cMessenger = msg.replyTo; cMessenger.send(message);
即完成了从服务端向客户端发送消息的功能,这样客服端可以在自己的Handler对象的handlerMessage方法中接收服务端发送来的message进行处理。
上面的一般方法大家可以自行百度,网上有很多资源。
**注意:**Message的obj不能设置为设置为non-Parcelable的对象,在跨进程的情形下,Message的obj设置为了一个String对象,那么在Messenger执行send(Message)方法时就会报如下错误: Java.lang.RuntimeException: Can’t marshal non-Parcelable objects across processes.
解决该问题最简单的办法是,在跨进程的时候不使用Message的obj,用Bundle传递数据,setData设置Bundle数据,getData获取Bundle数据。
AIDL
aidl是 Android Interface definition language的缩写,可以定义为进程间的通信接口。
AIDL的使用过程:
首先,创建一个aidl文件(不清楚的自行百度哈)
其次,创建一个Service类
public class Aidl_Service extends Service {
IMyAidlInterface.Stub stub=new IMyAidlInterface.Stub(){
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
Override
public String getName(String nickName) throws RemoteException {
return nickName+"aidi_hahah";
}
@Override
public int result(int a, int b) throws RemoteException {
return a+b;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
}
同样我们还可以自定义一些方法,然后编译一下,新加入的方法就可以被使用。
第三,在另一个activity中实现通信
private Button btn;
ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IMyAidlInterface iMyAidlInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aidl_layout);
btn = (Button) findViewById(R.id.aidl_btn);
bindService(new Intent(Aidl.this,Aidl_Service.class),connection, Context.BIND_AUTO_CREATE);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(iMyAidlInterface!=null){
try {
String name=iMyAidlInterface.getName("nick_know_maco");
int result=iMyAidlInterface.result(1,3);
Toast.makeText(Aidl.this,name+""+result,Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
最后,在AndroidManifest.xml中给service开辟一个新的进程,然后我们点击运行就可以实现了跨进程之间的通信。
Notification
Notification,俗称通知,是一种具有全局效果的通知,它展示在屏幕的顶端,首先会表现为一个图标的形式,当用户向下滑动的时候,展示出通知具体的内容。
通知一般通过NotificationManager服务来发送一个Notification对象来完成,NotificationManager是一个重要的系统级服务,该对象位于应用程序的框架层中,应用程序可以通过它像系统发送全局的通知。
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
MainActivity.this).setSmallIcon(R.drawable.one)
.setContentTitle("new message")
.setContentText("twain@android.com");
mBuilder.setTicker("New message");//第一次提示消息的时候显示在通知栏上
mBuilder.setNumber(12);
mBuilder.setLargeIcon(btm);
mBuilder.setAutoCancel(true);//自己维护通知的消失
//构建一个Intent
Intent resultIntent = new Intent(MainActivity.this,
ResultActivity.class);
//封装一个Intent
PendingIntent resultPendingIntent = PendingIntent.getActivity(
MainActivity.this, 0, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 设置通知主题的意图
mBuilder.setContentIntent(resultPendingIntent);
//获取通知管理器对象
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
这样我们就做好了。