RemoteCallbackList的使用:
使用android中的AIDL让Service与Activity通信(service回调activity)
在很多情况下是需要远程服务端主动给客户端返回数据,客户端只需要进行监听即可,这是典型的观察者模式。这篇文章主要来解决一下这个问题。
因为是跨进程的通信协议,需要创建两个项目,一个项目是后台程序,一个是启动该后台服务的客户端,通过启动这两个项目来演示2个进程间的通信。
步骤1:创建Service项目,将该项目中的Activity类删除,把AndroidManifest.xml中的activity配置删除。
Java代码:
package com.example.aidl3;
interface ICallback{
void showResult(int result);
}
再创建一个AIDL接口文件,命名为IService.aidl
Java代码:
package com.example.aidl3;
interface ICallback{
void showResult(int result);
}
步骤3:新建包结构com.example.aidlService3,自定义MyService.java类,该类继承Service类
Java代码:
package com.example.service3;
import com.example.aidl3.ICallback;
import com.example.aidl3.IService;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class MyService extends Service{
private static final String tag = "MyService";
private int value=0;
private static final int REPORT_MSG = 0;
private RemoteCallbackList<ICallback> myCallback=new RemoteCallbackList<ICallback>();
private IService.Stub mBinder=new IService.Stub() {
@Override
public void unregisterCallback(ICallback cb) throws RemoteException {
// TODO Auto-generated method stub
if(cb!=null){
myCallback.unregister(cb);
}
}
@Override
public void registerCallback(ICallback cb) throws RemoteException {
// TODO Auto-generated method stub
if(cb!=null){
myCallback.register(cb);
}
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
mHandler.sendEmptyMessage(REPORT_MSG);
}
@Override
public void onDestroy() {
mHandler.removeMessages(REPORT_MSG);
myCallback.kill();
super.onDestroy();
}
private void callBack() {
int N = myCallback.beginBroadcast();
int mValue=++value;
try {
for (int i = 0; i < N; i++) {
myCallback.getBroadcastItem(i).showResult(mValue);
}
mHandler.sendEmptyMessageDelayed(REPORT_MSG, 1*1000);
// Toast.makeText(getApplicationContext(), "showResult()"+mValue, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
myCallback.finishBroadcast();
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
callBack();
super.handleMessage(msg);
}
};
}
步骤4:
在 AndroidManifet.xml 中注册 Service
<service android:name="com.example.service3.MyService"
android:process=":remote"
android:exported="true">
<intent-filter >
<action android:name="com.service3"/>
</intent-filter>
</service>
</application>
服务端的结构如下:
步骤5:创建客户端,将Service项目中创建的ICallBack.aidl和IService.aidl接口连包一起复制到Client项目中
客户端的结构如下:
Java代码:
package com.example.client_aidl3_activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.aidl3.ICallback;
import com.example.aidl3.IService;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
public class MainActivity extends Activity implements OnClickListener{
private IService mService;
private TextView tv;
private Button btBinder;
private String mResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView) findViewById(R.id.tv);
btBinder=(Button) findViewById(R.id.bt_binder);
btBinder.setOnClickListener(this);
}
/**
* service的回调方法
*/
private ICallback.Stub mCallBack= new ICallback.Stub() {
@Override
public void showResult(int result) throws RemoteException {
// TODO Auto-generated method stub
Log.i("test", "showResult:"+result);
mResult=result+"";
// Message message=new Message();
//Message message=Message.obtain()避免分配新的对象,减少内存的开销
Message message=Message.obtain();
message.what=0;
handler.sendMessage(message);
}
};
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
tv.setText("result"+mResult);
break;
default:
break;
}
}
};
@Override
protected void onDestroy() {
if(mService!=null){
try {
mService.unregisterCallback(mCallBack);
} catch (RemoteException e) {
Log.e("TAG", "", e);
}
}
//destroy的时候不要忘记unbindService
unbindService(conn);
super.onDestroy();
}
private ServiceConnection conn= new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
mService=null;
tv.setText("unconnect");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mService=IService.Stub.asInterface(service);
try {
mService.registerCallback(mCallBack);
tv.setText("connect");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.bt_binder:
Intent intent=new Intent();
intent.setAction("com.service3");
intent.setPackage("com.example.aidl3");
bindService(intent, conn, BIND_AUTO_CREATE);
Toast.makeText(this, "server 已连接", Toast.LENGTH_SHORT).show();
break;
}
}
}
客户端activity_main.xml的代码如下
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.client_aidl3_activity.MainActivity" >
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
<Button
android:id="@+id/bt_binder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv"
android:layout_centerInParent="true"
android:text="binder"/>
</RelativeLayout>
这是本人这一个星期实习所学所写的关于Service跨进程调用服务的AIDL使用的总结的第三个,没有学过AIDL的朋友可以先查看前面两个例子。
Service跨进程调用服务三部曲之AIDL详解(一):http://blog.youkuaiyun.com/yzwty/article/details/51924121
Service跨进程调用服务三部曲之AIDL详解(二):http://blog.youkuaiyun.com/yzwty/article/details/51924364