Android开发艺术探索 - 第5章 理解RemoteViews

46 篇文章 0 订阅
39 篇文章 0 订阅
1.RemoteViews应用
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notication);
remoteViews.setTextViewText(R.id.text, "text");
remoteViews.setImageViewResource(R.id.image, R.drawable.icon);
remoteViews.setOnClickPendingIntent(R.id.button, 
        PendingIntent.getActivities(this, 0, 
                new Intent(this, TargetActivity.class), 
                PendingIntent.FLAG_UPDATE_CURRENT));
  1. 自定义通知布局
  2. 桌面小部件
  3. PendingIntent
getActivity(Context context, int requestCode, Intent intent, @Flags int flags)
getBroadcast(Context context, int requestCode, Intent intent, @Flags int flags)
getService(Context context, int requestCode, @NonNull Intent intent, @Flags int flags)
* PendingIntent用于描述Intent和target action,提供给其他application以执行相应的动作。
* 所以为了安全,要使用显示Intent,直接指定目标组件。
* PendingIntent标识了一组将要操作的数据,如果创建它的process被kill了,不影响其他process继续使用他;之后如果重新创建了一个相同类型的PendingIntent,之前同类型的如果可用将继续被使用。
* 相同的Intent将得到相同的PendingIntent,而Intent中extra的部分不会影响判断Intent是否相同。所以如果想得到不同PendingIntent,要保证Intent的不同(单独区分extra无效),或者在PendingIntent的get方法中指定不同的requestCode;如果同一时刻只想使用同一个PendingIntent,通过设置FLAG_CANCEL_CURRENT或FLAG_UPDATE_CURRENT来取消或更新指定的Intent。
* flags:
    * FLAG_ONE_SHOT
        该PendingIntent只能被使用一次。Intent被send之后会直接被cancel,之后send将失败。
    * FLAG_CANCEL_CURRENT
        如果当前描述的PendingIntent已经存在,则cancel,然后创建一个新的PendingIntent。
    * FLAG_UPDATE_CURRENT
        如果当前描述的PendingIntent已经存在,则替换其中Intent的extra。
2.RemoteViews内部机制

Remoteviews仅支持部分layout和view,不支持其子类和其他自定义View。
RemoteViews会通过Binder传递到SystemServer进程,在SystemServer中加载布局,更新View。具体流程:

  • 本地进程创建RemoteViews实例,然后调用了一系列的set方法设置了View。为了减少IPC开销,RemoteViews内部声明一个Action抽象类,并实现了Parcelable接口,将set调用的操作封装为一个action。而set方法实际上是创建了一个action,然后添加到自身维护的一个action list里面:
    public void setTextViewText(int viewId, CharSequence text) {
        setCharSequence(viewId, "setText", text);
    }
    public void setCharSequence(int viewId, String methodName, CharSequence value) {
        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));
    }
    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<>();
        }
        mActions.add(a);
    }
  • 在远程进程中,会调用RemoteViews的apply方法初始化View,调用performApply遍历action list,执行一系列的action操作来更新View:
/** @hide */
public View apply(Context context, ViewGroup parent, OnClickHandler handler) {
    RemoteViews rvToApply = getRemoteViewsToApply(context);

    View result = inflateView(context, rvToApply, parent);
    loadTransitionOverride(context, handler);

    rvToApply.performApply(result, parent, handler);

    return result;
}
private void performApply(View v, ViewGroup parent, OnClickHandler handler) {
    if (mActions != null) {
        handler = handler == null ? DEFAULT_ON_CLICK_HANDLER : handler;
        final int count = mActions.size();
        for (int i = 0; i < count; i++) {
            Action a = mActions.get(i);
            a.apply(v, parent, handler);
        }
    }
}
  • Action有很多实现,主要差异就在于其apply方法,如ReflectionAction的apply通过反射执行View的set方法,TextViewSizeAction的apply则直接对View调用setTextSize。ReflectionAction的抽象程度更高,支持的操作更多,但是反射会有一定的开销。
  • setOnClickPendingIntent仅支持给普通View设置click事件;组合setPendingIntentTemplate和setOnClickFillInIntent可以给ListView等的item设置click事件。
  • apply方法只负责将RemoteViews中维护的View创建出来,创建完成后需要将得到的View实例添加到hierarchy中。
  • 使用RemoteViews的reapply方法可以将一系列action操作执行到指定的View上。如可以在远程进程中自行创建同一个View,仅通过RemoteViews去执行View的更新操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值