理解RemoteViews————读书笔记

来源:互联网 发布:kk源码网 编辑:程序博客网 时间:2024/06/04 01:22

理解RemoteViews

RemoteViews的应用

RemoteViews在实际开发中主要用于通知栏和桌面小部件。

RemoteViews在通知栏上的应用

 Notification notification = new Notification();        notification.icon = R.drawable.ic_launcher;        notification.tickerText = "hello world";        notification.when = System.currentTimeMillis();        notification.flags = Notification.FLAG_AUTO_CANCEL;        Intent intent = new Intent(this, DemoActivity_1.class);        intent.putExtra("sid", "" + sId);        PendingIntent pendingIntent = PendingIntent.getActivity(this,                0, intent, PendingIntent.FLAG_UPDATE_CURRENT);        System.out.println(pendingIntent);        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notification);        remoteViews.setTextViewText(R.id.msg, "chapter_5: " + sId);        remoteViews.setImageViewResource(R.id.icon, R.drawable.icon1);        PendingIntent openActivity2PendingIntent = PendingIntent.getActivity(this,                0, new Intent(this, DemoActivity_2.class), PendingIntent.FLAG_UPDATE_CURRENT);        remoteViews.setOnClickPendingIntent(R.id.open_activity2, openActivity2PendingIntent);        notification.contentView = remoteViews;        notification.contentIntent = pendingIntent;        NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);        manager.notify(sId, notification);

只要提供当前应用的包名和布局文件的资源ID即可创建一个RemoteViews对象。更新RemoteViews只能使用setTextViewText, setImageViewResource, setOnClickPendingIntent等固定方法来设置View,不能像操作普通View的方式来操作。

RemoteViews在桌面小部件上的应用

AppWidgetProvider是Android中提供的用于实现桌面小部件的类,其本质是一个广播,即继承了BroadcastReceiver.
APPWidgetProvider的开发步骤:定义界面xml,定义配置信息xml,定义实现类(继承AppWidgetProvider),AndroidManifest中声明。
重要回调:onEnable,第一次被添加时调用,只有一次;onUpdate,添加或更新时回调;onDelete,每次删除时回调;onDisable,最后一次删除时回调;onReceive,接收广播的action。

PendingIntent

PendingIntent表示接下来有一个Intent将在某个待定的时刻发生。
1.典型的使用场景就是和RemoteViews的点击事件配合使用;
2.支持三种待定Intent:Activity,Service和Broadcast,主要方法:getActicity、getService、getBroadcast
3.PendingIntent相同的定义:内部的Intent和requestCode都相同。Intent相同的定义:两个Intent的componentName和intent-filter相同(不包括extras)
4.flag定义:FLAG_NO_CREATE,如果当前得PendingIntent之前不存在,那么getActicity、getService、getBroadcast方法直接返回null,即获取PendingIntent失败;FLAG_ONE_SHOT,以第一个为准,后续的会全部和第一条保持一致,任意一条被触发,其他的都cancel;FLAG_CANCEL_CURRENT,前面的相同的PendingIntent都会被cancel,只有最新的可用;FLAG_UDPATE_CURRENT,前面的PendingIntent都会被更新(它们Intent中的extras都会被更新)

RemoteViews的内部机制

1.RemoteViews的作用是在其他进程中显示并更新View界面,支持的View类型:Layout:FrameLayout, LinearLayout, RelativeLayout, GridLayout; View: AnalogClock, Button, Chronometer, ImageButton, ImageView, ProgressBar, TextView, ViewFlipper, ListView, GridView, StackView, AdapterViewFlipper, ViewStub。
2.源码分析:
RemoteViews#setBitmap

public void setBitmap(int viewId, String methodName, Bitmap value) {    addAction(new BitmapReflectionAction(viewId, methodName, value));}

RemoteViews#addAction

private void addAction(Action a) {    if (hasLandscapeAndPortraitLayouts()) {        throw new RuntimeException("RemoteViews specifying separate landscape and portrait" +                " layouts cannot be modified. Instead, fully configure the landscape and" +                " portrait layouts individually before constructing the combined layout.");    }    if (mActions == null) {        mActions = new ArrayList<Action>();    }    mActions.add(a);    // update the memory usage stats    a.updateMemoryUsageEstimate(mMemoryUsageCounter);    }

RemoteViews#apply

/** @hide */public View apply(Context context, ViewGroup parent, OnClickHandler handler) {    RemoteViews rvToApply = getRemoteViewsToApply(context);    View result;    // RemoteViews may be built by an application installed in another    // user. So build a context that loads resources from that user but    // still returns the current users userId so settings like data / time formats    // are loaded without requiring cross user persmissions.    final Context contextForResources = getContextForResources(context);    Context inflationContext = new ContextWrapper(context) {        @Override        public Resources getResources() {            return contextForResources.getResources();        }        @Override        public Resources.Theme getTheme() {            return contextForResources.getTheme();        }        @Override        public String getPackageName() {            return contextForResources.getPackageName();        }    };    LayoutInflater inflater = (LayoutInflater)            context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);    // Clone inflater so we load resources from correct context and    // we don't add a filter to the static version returned by getSystemService.    inflater = inflater.cloneInContext(inflationContext);    inflater.setFilter(this);    result = inflater.inflate(rvToApply.getLayoutId(), parent, false);    rvToApply.performApply(result, parent, handler);    return result;}

RemoteViews#ReflectionAction extends Action#apply

    @Override    public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {        final View view = root.findViewById(viewId);        if (view == null) return;        Class<?> param = getParameterType();        if (param == null) {            throw new ActionException("bad type: " + this.type);        }        try {            getMethod(view, this.methodName, param).invoke(view, wrapArg(this.value));        } catch (ActionException e) {            throw e;        } catch (Exception ex) {            throw new ActionException(ex);        }    }

RemoteViews#TextViewSizeAction extends Action

private class TextViewSizeAction extends Action {        public TextViewSizeAction(int viewId, int units, float size) {            this.viewId = viewId;            this.units = units;            this.size = size;        }        public TextViewSizeAction(Parcel parcel) {            viewId = parcel.readInt();            units = parcel.readInt();            size  = parcel.readFloat();        }        public void writeToParcel(Parcel dest, int flags) {            dest.writeInt(TAG);            dest.writeInt(viewId);            dest.writeInt(units);            dest.writeFloat(size);        }        @Override        public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {            final TextView target = (TextView) root.findViewById(viewId);            if (target == null) return;            target.setTextSize(units, size);        }        public String getActionName() {            return "TextViewSizeAction";        }        int units;        float size;        public final static int TAG = 13;    }

简单归纳,客户端的RemoteViews通过binder机制来传递到SystemServer进程,(RemoteViews本身也实现了Parcelable接口)。本地进程的View操作(一系列的set方法)都转化成一系列的Action对象,远程进程通过Action对象的apply方法就是真正操作View的地方。方法apply和reapply,前者会加载布局并更新界面,后者则只更新界面。

0 0
原创粉丝点击