您的位置:首页 > 移动开发 > Android开发

关于android进程间通信(handler、messenger、AIDL)

2015-12-18 18:06 477 查看
关于进程间通信,首先需要思考几个问题:

1.进程间通信适用什么场合?

2.进程和线程区别是什么?

3.Handler用于线程间通信,可以实现进程间通信吗?

4.跨进程通信messager

5.跨进程通信AIDL

就按照上边的步骤我们去开始了解并且熟悉进程间通信。

1.进程间通信

进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。但是,系统空间却是“公共场所”,所以内核显然可以提供这样的条件。除此以外,那就是双方都可以访问的外设了。

进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的程序进程,使之能在一个操作系统里同时运行。这使得一个程序能够在同一时间里处理许 多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的运行,进程之间必须互相通话。IPC接口就提供了这种可能性。每个 IPC方法均有它自己的优点和局限性,因此,对于单个程序而言使用所有的IPC方法是不常见的。

进程通信使用场合:

1)数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。

2)共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。

3)通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

4) 资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。

5)进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程通过与内核及其它进程之间的互相通信来协调它们的行为。

综上所述,对于android开发人员来说,就是你开发了两个app,要数据共享,而又不能对其他app共享,比如账号密码。

2.进程和线程

进程是具有一定独立功能的程序,是系统进行资源分配和调度的一个独立单位。

线程是进程中的一个实体,是cpu分配资源和调度的基本单位

一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程。

进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

3.Handler

主要接受子线程发送的数据, 并用此数据配合主线程更新UI

handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:

(1)安排消息或Runnable 在某个主线程中某个地方执行;

(2)安排一个动作在不同的线程中执行

使用:

首先,我们定义两个service,一个默认进程,一个在remote进程。

默认进程service

public class ThreadHandlerService extends Service {
public ThreadHandlerService() {
}

@Override
public IBinder onBind(Intent intent) {
return new ThreadLocalBinder();
}

public void sayHi(){
Toast.makeText(ThreadHandlerService.this, "Hi,I'm thread service!", Toast.LENGTH_SHORT).show();
}

public class ThreadLocalBinder extends Binder{

public ThreadHandlerService getService(){

return ThreadHandlerService.this;
}
}
}


remote service

<span style="font-size:18px;">public class ProHandlerService extends Service {
public ProHandlerService() {
}

@Override
public IBinder onBind(Intent intent) {
return new ProLocalBinder();
}

public void sayHi(){
Toast.makeText(ProHandlerService.this, "Hi,I'm pro service!", Toast.LENGTH_SHORT).show();
}

public class ProLocalBinder extends Binder{

public ProHandlerService getService(){

return ProHandlerService.this;
}
}
}</span>


他们的代码基本相似,区别不在这里,而是在配置文件

<span style="font-size:18px;"><service
android:name=".service.ThreadHandlerService"
android:enabled="true"
android:exported="true" />
<service
android:name=".service.ProHandlerService"
android:enabled="true"
android:exported="true"
android:process=":remote" /></span>


接下来我们创建两个activity去绑定这两个service,进行连接

public class ThreadConHandlerActivity extends AppCompatActivity {

private ServiceConnection serviceConnection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_con);
initVIew();
}

private void initVIew() {
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("", "service connected");
ThreadHandlerService threadHandlerService = ((ThreadHandlerService.ThreadLocalBinder)service).getService();
threadHandlerService.sayHi();
}

@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("", "service disconnected");
}
};
}

@Override
protected void onStart() {
super.onStart();
Intent service = new Intent(this.getApplicationContext(),ThreadHandlerService.class);
this.bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
super.onStop();
this.unbindService(serviceConnection);
}
}


你会发现handler是无法在跨进程的线程中传递message的。原因?下篇博文介绍,这里就不重点说了。

4.Messenger

Messager实现IPC通信,底层使用了AIDL方式。和AIDL方式不同的是,Messager方式是利用Handler形式处理,因 此,它是线程安全的,这也表示它不支持并发处理;而AIDL方式是非线程安全的,支持并发处理,因此,我们使用AIDL方式时需要保证代码的线程安全。

大部分情况下,我们应用中不需要并发处理,只需要使用Messager方式

接入代码:

service

public class ProConMessagerService extends Service {

public static final int MSG_SAY_HELLO = 1;

public ProConMessagerService() {
}

@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}

Handler incomingHandler = new Handler() {

@Override
public void handleMessage(Message msg) {
if(msg.replyTo != null){
Message msg_client = this.obtainMessage();
msg_client.what = ProConMessagerActivity.SAY_HELLO_TO_CLIENT;
msg_client.replyTo = messenger;
try {
((Messenger) msg.replyTo).send(msg_client);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
switch (msg.what) {
case MSG_SAY_HELLO:
//                    Toast.makeText(ProConMessagerService.this.getApplicationContext(), "Hello World Remote Service!",
//                            Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}

};

Messenger messenger =new Messenger(incomingHandler);

}


activity

public class ProConMessagerActivity extends AppCompatActivity {

String TAG = "ProConMessagerActivity";
private ServiceConnection mSc;
public static final int SAY_HELLO_TO_CLIENT = 1;
private ListView remoteLv;
private MessageAdapter messageAdapter;
private List<MessageInfo> list = new ArrayList<MessageInfo>();
private int count =0;
Messenger messenger_reciever = new Messenger(new IncomingHandler());

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pro_con_messager);
initView();
}
private void initView() {
remoteLv = (ListView)findViewById(R.id.activity_pro_con_messager_lv);
messageAdapter = new MessageAdapter(this);
remoteLv.setAdapter(messageAdapter);
mSc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MessageInfo info = new MessageInfo();
info.setSender("system");
info.setReceiver("server,client");
info.setContent("Hello,service connected");
info.setCreateTime(String.valueOf(System.currentTimeMillis()));
list.add(info);
messageAdapter.setList(list);
Messenger messenger = new Messenger(service);
Message msg = new Message();
msg.what = ProConMessagerService.MSG_SAY_HELLO;
msg.replyTo = messenger_reciever;
try {
messenger.send(msg);
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
// 在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.
Log.d(TAG, "service disconnected");
MessageInfo info = new MessageInfo();
info.setSender("system");
info.setReceiver("server,client");
info.setContent("Hello,service disconnected");
info.setCreateTime(String.valueOf(System.currentTimeMillis()));
list.add(info);
messageAdapter.setList(list);
}
};
}

class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SAY_HELLO_TO_CLIENT:
MessageInfo info = new MessageInfo();
info.setSender("client");
info.setReceiver("server");
info.setContent("Hello,Server");
info.setCreateTime(String.valueOf(System.currentTimeMillis()));
list.add(info);
messageAdapter.setList(list);
//                    Toast.makeText(ProConMessagerActivity.this.getApplicationContext(), "Hello World Remote Client!",
//                            Toast.LENGTH_SHORT).show();
Message msgToServer = new Message();
msgToServer.what = ProConMessagerService.MSG_SAY_HELLO;
msgToServer.replyTo = messenger_reciever;
try {
if(count<5){
count++;
((Messenger) (msg.replyTo)).send(msgToServer);
info = new MessageInfo();
info.setSender("server");
info.setReceiver("client");
info.setContent("Hello,Client!" );
info.setCreateTime(String.valueOf(System.currentTimeMillis()));
list.add(info);
messageAdapter.setList(list);
}else{
try {
ProConMessagerActivity. this.unbindService(mSc);
Log.d(TAG, "service disconnected");
info = new MessageInfo();
info.setSender("system");
info.setReceiver("server,client");
info.setContent("Hello,service disconnected");
info.setCreateTime(String.valueOf(System.currentTimeMillis()));
list.add(info);
messageAdapter.setList(list);
} catch (Exception e) {
e.printStackTrace();
}
}

} catch (Exception e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}

@Override
protected void onStart() {
super.onStart();
Log.d(TAG, this.getApplicationContext().getPackageCodePath());
Intent service = new Intent(this.getApplicationContext(),ProConMessagerService.class);
this.bindService(service, mSc, Context.BIND_AUTO_CREATE);
}

@Override
protected void onPause() {
super.onPause();
try {
this.unbindService(mSc);
Log.d(TAG, "service disconnected");
MessageInfo info = new MessageInfo();
info.setSender("system");
info.setReceiver("server,client");
info.setContent("Hello,service disconnected");
info.setCreateTime(String.valueOf(System.currentTimeMillis()));
list.add(info);
messageAdapter.setList(list);
} catch (Exception e) {
e.printStackTrace();
}
}
}


5.AIDL

AIDL(Android Interface Definition Language)是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。

首先,你需要熟悉一下AIDL的使用,

server端:

创建.aidl文件

实现接口(如果你是使用android studio,发现找不到接口类,你可以先clean下)

client端:

copy server端的aidl到client端aidl下,包名用server端的。

调用远端接口的步骤:

1. 声明.aidl文件中定义的接口类型的变量。

2. 实现ServiceConnection

3. 调用Context.bindService(),传递ServiceConnection的实现

4. 在ServiceConnection.onServiceConnected()方法中会接收到IBinder对象,调用YourInterfaceName.Stub.asInterface((IBinder)service)将返回值转换为YourInterface类型

5. 调用接口中定义的方法。应该总是捕获连接被打断时抛出的DeadObjectException异常,这是远端方法唯一的异常。

6. 调用Context.unbindService()断开连接

贴上部分代码:

public class ProConAidlActivity extends AppCompatActivity implements View.OnClickListener{

private Button bindBtn,greetBtn,unbindBtn;

private IPerson person;
private ServiceConnection mSc;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pro_con_aidl);
initView();
}

private void initView() {
bindBtn = (Button)findViewById(R.id.activity_pro_con_aidl_bind);
greetBtn = (Button)findViewById(R.id.activity_pro_con_aidl_greet);
unbindBtn = (Button)findViewById(R.id.activity_pro_con_aidl_unbind);
bindBtn.setOnClickListener(this);
greetBtn.setOnClickListener(this);
unbindBtn.setOnClickListener(this);
bindBtn.setEnabled(true);
greetBtn.setEnabled(false);
unbindBtn.setEnabled(false);
mSc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
person = IPerson.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};
}

@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.activity_pro_con_aidl_bind:
Intent intent = new Intent("android.intent.action.AIDLService");
bindService(intent, mSc, Context.BIND_AUTO_CREATE);
Log.e("","service connected!");
bindBtn.setEnabled(false);
greetBtn.setEnabled(true);
unbindBtn.setEnabled(true);
break;
case R.id.activity_pro_con_aidl_greet:
try {
String retVal = person.greet("aidl ,no do no die");
Toast.makeText(ProConAidlActivity.this, retVal, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
Toast.makeText(ProConAidlActivity.this, "error", Toast.LENGTH_SHORT).show();
}
break;
case R.id.activity_pro_con_aidl_unbind:
unbindService(mSc);
Log.e("", "service disconnected!");
bindBtn.setEnabled(true);
greetBtn.setEnabled(false);
unbindBtn.setEnabled(false);
break;
}
}
}


项目下载地址:下载页面
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: