RemoteViews简单学习记录

remoteview最简单的应用应该就是在notification里面了,以下为简单示例。

public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            String channelID = "1";
            String channelName = "channel_name";

            NotificationChannel channel = null;
            channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            manager.createNotificationChannel(channel);
            // 利用channelName可以在系统设置页面对app某个名称的通知进行管理
            NotificationCompat.Builder builder =new NotificationCompat.Builder(this, channelName);
            Intent intent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

            RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notificaiton);
            remoteViews.setTextViewText(R.id.tv_5_s, "Start");//通过id-内容的方式设置remoteview中控件的内容,底层实现是通过Binder跨进程通信
            remoteViews.setTextViewText(R.id.tv_5_e, "End");
            remoteViews.setImageViewResource(R.id.icon_5, R.drawable.test);
            remoteViews.setOnClickPendingIntent(R.id.tv_5_e, pendingIntent);

            builder.setContent(remoteViews);
            builder.setSmallIcon(R.mipmap.ic_launcher);
            //创建通知时指定channelID
            builder.setChannelId(channelID);
            Notification notification = builder.build();
            manager.notify(1, notification);
        }
    }
}

如果是8.0以下系统,notification不用设置channelID ,代码如下所示

            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            Notification.Builder builder =new Notification.Builder(this);
            Intent intent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notificaiton);
            remoteViews.setTextViewText(R.id.tv_5_s, "Start");//通过id-内容的方式设置remoteview中控件的内容,底层实现是通过Binder跨进程通信
            remoteViews.setTextViewText(R.id.tv_5_e, "End");
            remoteViews.setImageViewResource(R.id.icon_5, R.drawable.test);
            remoteViews.setOnClickPendingIntent(R.id.tv_5_e, pendingIntent);

            builder.setCustomContentView(remoteViews);
            builder.setSmallIcon(R.mipmap.ic_launcher);

            Notification notification = builder.build();
            manager.notify(1, notification);


    
    
    

通过在notification中简单使用remoteview可以对其有一个简单的了解。

以下文字出处:https://www.jianshu.com/p/91c30eb0a90b
RemoteViews的原理
RemoteViews本身并不是个View.它是个Pacelable,是个可以跨进程传递的一个数据.它携带了UI的布局及对应的数据
其它进程收到这个RemoteViews后会在其进程中根据这个布局inflat出对应的View.然后根据RemoteViews里的属性反射设置到对应的View上,然后根据设置点击监听.监听的处理就是调用对应的PendingIntent.
因为是跨进程,所以无法直接操作View,所以系统把对view的一个操作定义为Action对象.Action对象本身也是个Pacelable,所以可以跨进程.其封装了操作View的数据.远程进程遍历所有的Action并执行其apply方法通过反射更新View
向先前说的设置view的属性,设置点击监听,都是一个Action.

这种说法对我而言太过抽象。

//vendor\mediatek\proprietary\packages\apps_700_es\SystemUI_700_es\src\com\android\systemui\statusbar\notification\NotificationInflater.java
        @Override
        protected InflationProgress doInBackground(Void... params) {
            try {
                final Notification.Builder recoveredBuilder
                        = Notification.Builder.recoverBuilder(mContext,
                        mSbn.getNotification());
                Context packageContext = mSbn.getPackageContext(mContext);
                Notification notification = mSbn.getNotification();
                if (mIsLowPriority) {
                    int backgroundColor = mContext.getColor(
                            R.color.notification_material_background_low_priority_color);
                    recoveredBuilder.setBackgroundColorHint(backgroundColor);
                }
                if (notification.isMediaNotification()) {
                    MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
                            packageContext);
                    processor.setIsLowPriority(mIsLowPriority);
                    processor.processNotification(notification, recoveredBuilder);
                }
                return createRemoteViews(mReInflateFlags,
                        recoveredBuilder, mIsLowPriority, mIsChildInGroup,
                        mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
                        packageContext);
            } catch (Exception e) {
                mError = e;
                return null;
            }
        }

   private static InflationProgress createRemoteViews(int reInflateFlags,
            Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
            boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
            Context packageContext) {
        InflationProgress result = new InflationProgress();
        isLowPriority = isLowPriority && !isChildInGroup;
        if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
            result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
        }

        if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
            result.newExpandedView = createExpandedView(builder, isLowPriority);
        }

        if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
            result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
        }

        if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
            result.newPublicView = builder.makePublicContentView();
        }

        if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
            result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
                    : builder.makeAmbientNotification();
        }
        result.packageContext = packageContext;
        return result;
    }

NotificationInflater中的createRemoteViews这里我没有深入看下去,从方法名字上来看是这里创建了remoteview。

RemoteViews 本身的属性并不多,这里重点关注了一下mLayoutId和mActions,以及ReflectionAction。

//frameworks\base\core\java\android\widget\RemoteViews.java
public class RemoteViews implements Parcelable, Filter {

    /**
     * The resource ID of the layout file. (Added to the parcel)
     */
    private final int mLayoutId;
    /**
     * An array of actions to perform on the view tree once it has been
     * inflated
     */
    private ArrayList mActions;

    /**
     * Inflates the view hierarchy represented by this object and applies
     * all of the actions.
     *
     * 

Caller beware: this may throw * * @param context Default context to use * @param parent Parent that the resulting view hierarchy will be attached to. This method * does not attach the hierarchy. The caller should do so when appropriate. * @return The inflated view hierarchy */ public View apply(Context context, ViewGroup parent) { return apply(context, parent, null); } /** @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); } } } private final class ReflectionAction extends Action { ReflectionAction(int viewId, String methodName, int type, Object value) { this.viewId = viewId; this.methodName = methodName; this.type = type; this.value = value; } } } ................... }

大部分资料显示remoteview更新ui调用的是apply,但是在此过程中ReflectionAction 到底做了什么对此我有些疑惑。于是在ReflectionAction构造函数中打印log(对于反射这一块我存在知识盲区待补),结果如下所示。

2010-01-03 04:33:15.328 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{10b0fc2 VFED..... ........ 48,0-79,48 #7f0700c1 app:id/tv_5_s} ,value = Start
2010-01-03 04:33:15.329 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{28f01d3 VFED..C.. ........ 408,0-432,48 #7f0700c0 app:id/tv_5_e} ,value = End
2010-01-03 04:33:15.341 966-966/? D/RemoteViews: methodName = setExpanded , param = boolean ,view = android.view.NotificationHeaderView{5a44110 V.E...... R.....ID 0,0-480,48 #102032b android:id/notification_header} ,value = false
2010-01-03 04:33:15.341 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{f7e660e V.ED..... ......ID 40,15-121,32 #10201af android:id/app_name_text} ,value = null
2010-01-03 04:33:15.342 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{8bde82f G.ED..... ......I. 0,0-0,0 #1020281 android:id/header_text} ,value = 8
2010-01-03 04:33:15.342 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{8bde82f G.ED..... ......I. 0,0-0,0 #1020281 android:id/header_text} ,value = null
2010-01-03 04:33:15.342 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{8f45e3c G.ED..... ......I. 0,0-0,0 #1020282 android:id/header_text_divider} ,value = 8
2010-01-03 04:33:15.342 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{32a97c5 V.ED..... ......ID 125,15-129,32 #102043f android:id/time_divider} ,value = 8
2010-01-03 04:33:15.343 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.DateTimeView{abed51a V.ED..... ......ID 133,15-151,32 #102043b android:id/time} ,value = 8
2010-01-03 04:33:15.343 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.ImageView{44ad84b G.ED..... ......I. 0,0-0,0 #102037c android:id/profile_badge} ,value = 8
2010-01-03 04:33:15.344 966-966/? D/RemoteViews: methodName = setOriginalIconColor , param = int ,view = android.view.NotificationHeaderView{5a44110 V.E...... R.....ID 0,0-480,48 #102032b android:id/notification_header} ,value = -9079435
2010-01-03 04:33:15.345 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{f7e660e V.ED..... ......ID 40,15-121,32 #10201af android:id/app_name_text} ,value = My Application
2010-01-03 04:33:15.345 966-966/? D/RemoteViews: methodName = setTextColor , param = int ,view = android.widget.TextView{f7e660e V.ED..... ......ID 40,15-121,32 #10201af android:id/app_name_text} ,value = -9079435
2010-01-03 04:33:15.345 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{32a97c5 G.ED..... ......ID 125,15-129,32 #102043f android:id/time_divider} ,value = 0
2010-01-03 04:33:15.345 966-966/? D/RemoteViews: methodName = setTextColor , param = int ,view = android.widget.TextView{32a97c5 V.ED..... ......ID 125,15-129,32 #102043f android:id/time_divider} ,value = -1979711488
2010-01-03 04:33:15.345 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.DateTimeView{abed51a G.ED..... ......ID 133,15-151,32 #102043b android:id/time} ,value = 0
2010-01-03 04:33:15.346 966-966/? D/RemoteViews: methodName = setTime , param = long ,view = android.widget.DateTimeView{abed51a V.ED..... ......ID 133,15-151,32 #102043b android:id/time} ,value = 1262464395151
2010-01-03 04:33:15.353 966-966/? D/RemoteViews: methodName = setTextColor , param = int ,view = android.widget.DateTimeView{abed51a V.ED..... ......ID 133,15-151,32 #102043b android:id/time} ,value = -1979711488
2010-01-03 04:33:15.353 966-966/? D/RemoteViews: methodName = setOriginalNotificationColor , param = int ,view = android.view.NotificationHeaderView{5a44110 V.E...... R.....ID 0,0-480,48 #102032b android:id/notification_header} ,value = -9079435
2010-01-03 04:33:15.353 966-966/? D/RemoteViews: methodName = setExpandOnlyOnButton , param = boolean ,view = android.view.NotificationHeaderView{5a44110 V.E...... R.....ID 0,0-480,48 #102032b android:id/notification_header} ,value = true
2010-01-03 04:33:15.354 966-966/? D/RemoteViews: methodName = setExpanded , param = boolean ,view = android.view.NotificationHeaderView{221eb41 V.E...... ......ID 16,0-464,48 #102032b android:id/notification_header} ,value = false
2010-01-03 04:33:15.355 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{36528e6 I.ED..... ......ID 42,14-134,33 #10201af android:id/app_name_text} ,value = null
2010-01-03 04:33:15.355 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{c6cae27 G.ED..... ......I. 0,0-0,0 #1020281 android:id/header_text} ,value = 8
2010-01-03 04:33:15.355 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{c6cae27 G.ED..... ......I. 0,0-0,0 #1020281 android:id/header_text} ,value = null
2010-01-03 04:33:15.355 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{8038d4 G.ED..... ......I. 0,0-0,0 #1020282 android:id/header_text_divider} ,value = 8
2010-01-03 04:33:15.356 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{fe0fa7d G.ED..... ......I. 0,0-0,0 #102043f android:id/time_divider} ,value = 8
2010-01-03 04:33:15.356 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.DateTimeView{8caed72 G.ED..... ......I. 0,0-0,0 #102043b android:id/time} ,value = 8
2010-01-03 04:33:15.356 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.ImageView{aec05c3 G.ED..... ......I. 0,0-0,0 #102037c android:id/profile_badge} ,value = 8
2010-01-03 04:33:15.356 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{8120e40 G.ED..... ......ID 0,0-0,0 #1020016 android:id/title} ,value = 8
2010-01-03 04:33:15.356 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{8120e40 G.ED..... ......ID 0,0-0,0 #1020016 android:id/title} ,value = null
2010-01-03 04:33:15.356 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.TextView{587c179 G.ED..... ......I. 0,0-0,0 #102041e android:id/text} ,value = 8
2010-01-03 04:33:15.356 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{587c179 G.ED..... ......I. 0,0-0,0 #102041e android:id/text} ,value = null
2010-01-03 04:33:15.357 966-966/? D/RemoteViews: methodName = setBackgroundResource , param = int ,view = android.widget.FrameLayout{4566ebe I.E...... R.....ID 0,0-480,48 #102040b android:id/status_bar_latest_event_content} ,value = 0
2010-01-03 04:33:15.358 966-966/? D/RemoteViews: methodName = setOriginalIconColor , param = int ,view = android.view.NotificationHeaderView{221eb41 V.E...... ......ID 16,0-464,48 #102032b android:id/notification_header} ,value = -3947581
2010-01-03 04:33:15.358 966-966/? D/RemoteViews: methodName = setText , param = interface java.lang.CharSequence ,view = android.widget.TextView{36528e6 I.ED..... ......ID 42,14-134,33 #10201af android:id/app_name_text} ,value = My Application
2010-01-03 04:33:15.359 966-966/? D/RemoteViews: methodName = setTextColor , param = int ,view = android.widget.TextView{36528e6 I.ED..... ......ID 42,14-134,33 #10201af android:id/app_name_text} ,value = -3947581
2010-01-03 04:33:15.359 966-966/? D/RemoteViews: methodName = setOriginalNotificationColor , param = int ,view = android.view.NotificationHeaderView{221eb41 V.E...... ......ID 16,0-464,48 #102032b android:id/notification_header} ,value = -9079435
2010-01-03 04:33:15.359 966-966/? D/RemoteViews: methodName = setMinimumHeight , param = int ,view = android.widget.LinearLayout{37f3b1f V.E...... ......ID 0,4-448,4 #102032c android:id/notification_main_column} ,value = 0
2010-01-03 04:33:15.359 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = com.android.internal.widget.NotificationActionListLayout{a29ce6c G.E...... ......ID 0,0-0,0 #102018d android:id/actions} ,value = 8
2010-01-03 04:33:15.359 966-966/? D/RemoteViews: methodName = setEmphasizedMode , param = boolean ,view = com.android.internal.widget.NotificationActionListLayout{a29ce6c G.E...... ......ID 0,0-0,0 #102018d android:id/actions} ,value = false
2010-01-03 04:33:15.360 966-966/? D/RemoteViews: methodName = setVisibility , param = int ,view = android.widget.FrameLayout{439fc35 G.E...... ......I. 0,0-0,0 #102018e android:id/actions_container} ,value = 8

由于原理的理解重点还是在反射那一块,因此暂不深入。
整个流程看下来,remoteview无法直接通过findview获取到view从而进行操作,需要使用action。

参考链接:
Android开发艺术探索 第5章 理解RemoteViews 读书笔记

Android中的RemoteViews

Android通知及RemoteViews整理

Android View - RemoteViews

你可能感兴趣的:(RemoteViews简单学习记录)