本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
转载请注明 http://blog.csdn.net/wrg_20100512/article/details/53940485
好久没有写博客了,主要是忙着找工作和做毕业设计,没有时间来看一些值得分享的东西。今天写这篇博客是因为我被安排了解下RemoteViews。说实话,这个东西真心没有看过,仅仅看《Android艺术开发探索》的时候知道有这么个“控件”,还记得任主席在群里说过这是他这本书中最自豪的一章,有没有之一我就不清楚啦!话不多说,那就开始Android神奇“控件”之旅吧!
RemoteViews是什么?
先从表层意思理解RemoteViews感觉它是一个view的集合,而且和远程有关系。那事实上它是什么呢?请看官方对它的说明:
从说明可以看出,RemoteViews是用来描述一个视图的,它描述的这个视图将显示在另外一个进程中,这也就符合了RemoteViews中Remote这层含义。同时说明里也说了RemoteViews提供了一些基本的操作方法来修改它描述的那个视图的内容。听起来它还真像是个“控件”,那它真的是吗?
看一下RemoteViews的类继承关系:
从图中发现,RemoteViews与View没有半毛钱的关系,它仅仅就是Object的一个子类,实现了Parcelable接口(这就为RemoteViews能够实现跨进程提供了条件)。所以从严格意义上来说,RemoteViews并不是一个控件,它仅仅是为生成控件和修改控件属性提供一系列的方法。
总结:RemoteViews就是为跨进程生成控件和修改控件属性提供一系列方法的一个类。
说了RemoteViews是什么之后,咱们来看看为什么要用RemoteViews!
为什么要用RemoteViews?
既然RemoteViews是用于跨进程更新UI的,那咱们就来创造这么一个场景:
同一个应用中有两个Activity,这两个Activity分别处在不同的进程中
MainActivity TempActivity
其中MainActivity所属的进程为com.example.bjwangruigang.remoteviewstudy,TempActivity所属的进程为com.example.bjwangruigang.remoteviewstudy:remote。现在需要通过TempActivity来改变MainActivity中的视图,也就是实现跨进程更新UI这么一个功能。具体来说就是在MainActivity中添加两个Button。
传统方式实现跨进程更新UI
拿到这个场景需求,结合跨进程和更新UI的知识,有以下几个方案:
TempActivity把要添加的两个Button的布局的ID值通过BroadcastRecriver发送,在MainActivity中注册该广播,同时获取其中的布局ID值,通过LayoutInflater来绘制那两个Button,最后添加到MainActivity的布局中去。
TempActivity通过AIDL这种方式将要添加的两个Button的布局的ID值发送到AIDLService中,通过Handler来发送消息、处理消息。处理过程同样是通过LayoutInflater来绘制那两个Button,最后添加到MainActivity的布局中去。
其实这两种方案大同小异,无非采用的进程间通信方式不同,后续的添加视图是一模一样的。方案一采用广播的形式来进行IPC通信,而方案二则采用AIDL这种相对原生的IPC方式。为了重温AIDL,这里我采用AIDL 的方式来实现上述效果。
首先建立IViewManager.aidl。
interface IViewManager {
void setTextViewText(in int id,in String text);//设置TextView的内容
void addView(in int layoutId); //添加View视图
}
rebuild project让IDE工具自己生成AIDL借口对应的java文件。
建立ViewAIDLService文件。
public class ViewAIDLService extends Service {
private static final String TAG = "ViewAIDLService";
private Binder viewManager = new IViewManager.Stub(){
@Override
public void setTextViewText(int id, String text) throws RemoteException {
Message message = new Message();
message.what = 2;
Bundle bundle = new Bundle();
bundle.putInt("id",id);
bundle.putString("text",text);
message.setData(bundle);
new MainActivity.MyHandler(ViewAIDLService.this,getMainLooper()).sendMessage(message);
}
@Override
public void addView(int layoutId) throws RemoteException {
Message message = new Message();
message.what = 3;
Bundle bundle = new Bundle();
bundle.putInt("layoutId",layoutId);
message.setData(bundle);
Log.i(TAG,"thread name = "+Thread.currentThread().getName());
new MainActivity.MyHandler(ViewAIDLService.this,getMainLooper()).sendMessage(message);
}
};
public ViewAIDLService() {
}
@Override
public IBinder onBind(Intent intent) {
return viewManager;
}
}
在TempActivity中绑定服务,并在绑定成功后,针对实现的功能调用不同的远程方法。
private ServiceConnection viewServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG,"onServiceConnected");
IViewManager viewsManager = IViewManager.Stub.asInterface(service);
try {
viewsManager.setTextViewText(R.id.text,"通过AIDL跨进程修改TextView内容");
viewsManager.addView(R.layout.layout);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override