美文网首页
RemoteViews简单学习记录

RemoteViews简单学习记录

作者: 梧叶已秋声 | 来源:发表于2019-12-23 11:26 被阅读0次

    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);
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="48dp" android:orientation="vertical"
        android:paddingEnd="48dp"
        android:paddingStart="48dp"
        android:focusable="true">
    
        <ImageView
            android:id="@+id/icon_5"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_centerInParent="true"
            android:src="@mipmap/ic_launcher_round" />
        <TextView
            android:id="@+id/tv_5_s"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentStart="true"
            android:gravity="center_vertical"
            android:text="Left"
            android:focusable="true"/>
        <TextView
            android:id="@+id/tv_5_e"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:gravity="center_vertical"
            android:text="Right"
            android:focusable="true"/>
    </RelativeLayout>
    

    通过在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<Action> mActions;
    
        /**
         * Inflates the view hierarchy represented by this object and applies
         * all of the actions.
         *
         * <p><strong>Caller beware: this may throw</strong>
         *
         * @param context Default context to use
         * @param parent Parent that the resulting view hierarchy will be attached to. This method
         * does <strong>not</strong> 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简单学习记录

          本文链接:https://www.haomeiwen.com/subject/waxonctx.html