RemoteViews跨进程显示机制

目录

1.使用场景:

2.与View的区别:

3.Action介绍:

4.Action怎么转化为View的流程:

5.总结:


1.使用场景:

RemoteViews最常用的使用场景就是通知(Notification)的显示和桌面小控件的显示(Widget)

2.与View的区别:

RemoteViews与View的最主要的区别就是是否支持跨进程使用。

RemoteViews实现了Parcelable(序列化)接口,数据是支持跨进程传输的,而View没有实现Parcelable或Serializable(打包)接口,因此是不支持跨进程使用的。

View是Android UI控件的父类,也就是说它能够显示在界面上,能够让用户看到,而RemoteViews可以理解为一个工具类,它只是将数据存储并传输到另一个进程,在另一个进程中创建对应的View显示,并对View进行初始化操作。

在使用RemoteViews时不得不管在其apply,此方法是RemoteViews转化为View的纽带,源码如下:

/**
 * 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);
}

通过此方法的入参以及返回值就可以具体了解RemoteViews与View的关系了,最终可以总结为一句话“RemoteViews是支持跨进程传输数据的创建View的一个工具类”。

3.Action介绍:

从上面RemoteViews的定义知道它是支持跨进程传输的,同时View的创建都是在另外一个进程中,而我们可以在本进程中调用set方法对相关View进行初始化,但这块功能具体是怎么实现的呢?

RemoteViews的对View操作的set方法具体实现实际上就依赖Action了,在调用set方法时,会新建一个Action将操作存储下来,并将所有的Action都传到另一个进程中,在apply方法中执行所有的Action操作。

/**
 * Base class for all actions that can be performed on an
 * inflated view.
 *
 *  SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
 */
private abstract static class Action implements Parcelable {

这个Action是一个抽象的基类,他有众多的派生类,来具体看看每一个派生类的作用:

  • RuntimeAction

功能:在RemoteViews转换View的inflation阶段使用,也就是说在布局的xml文件转换为响应的View阶段使用,它是不支持跨进程使用的,从使用阶段上就可以看出,它只在另一个进程中使用,因此不需要支持跨进程。

/**
 * Action class used during async inflation of RemoteViews. Subclasses are not parcelable.
 */
private static abstract class RuntimeAction extends Action {
    @Override
    public final String getActionName() {
        return "RuntimeAction";
    }

    @Override
    public final void writeToParcel(Parcel dest, int flags) {
        throw new UnsupportedOperationException();
    }
}

从继承关系上看是支持跨进程传输的,但是它重写了wirteToParces,并直接抛出一个异常,这就导致当跨进程传输数据时无法向通道中写入数据,从而就导致了不支持跨进程传输了。

  • ActionException

作用:执行Action发生错误时抛出此异常,它只运行在另一个进程中,并且不支持跨进程。

继承关系:Action -> RuntimeAction -> ActionException

  • RunnableAction

作用:异步执行Action时使用,它只运行在另一个进程中,并且不支持跨进程。

继承关系:Action -> RuntimeAction -> RunnableAction

  • BitmapReflectionAction

作用:参数为Bitmap(支持跨进程传输)的操作,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> BitmapReflectionAction

例如:ImageVeiw的setImageBitmap

/**
 * Equivalent to calling {@link ImageView#setImageBitmap(Bitmap)}
 *
 * @param viewId The id of the view whose bitmap should change
 * @param bitmap The new Bitmap for the drawable
 */
public void setImageViewBitmap(int viewId, Bitmap bitmap) {
    setBitmap(viewId, "setImageBitmap", bitmap);
}
  • LayoutParamAction

作用:LayoutParam相关参数的设置,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> BitmapReflectionAction

3189    /**
3190     * @hide
3191     * Equivalent to calling {@link android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)}.
3192     * Only works if the {@link View#getLayoutParams()} supports margins.
3193     * Hidden for now since we don't want to support this for all different layout margins yet.
3194     *
3195     * @param viewId The id of the view to change
3196     * @param endMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
3197     */
3198    public void setViewLayoutMarginEndDimen(int viewId, @DimenRes int endMarginDimen) {
3199        addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END_DIMEN,
3200                endMarginDimen));
3201    }
3202
3203    /**
3204     * Equivalent to setting {@link android.view.ViewGroup.MarginLayoutParams#bottomMargin}.
3205     *
3206     * @param bottomMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
3207     * @hide
3208     */
3209    public void setViewLayoutMarginBottomDimen(int viewId, @DimenRes int bottomMarginDimen) {
3210        addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_BOTTOM_DIMEN,
3211                bottomMarginDimen));
3212    }
3213
3214    /**
3215     * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}.
3216     *
3217     * @param layoutWidth one of 0, MATCH_PARENT or WRAP_CONTENT. Other sizes are not allowed
3218     *                    because they behave poorly when the density changes.
3219     * @hide
3220     */
3221    public void setViewLayoutWidth(int viewId, int layoutWidth) {
3222        if (layoutWidth != 0 && layoutWidth != ViewGroup.LayoutParams.MATCH_PARENT
3223                && layoutWidth != ViewGroup.LayoutParams.WRAP_CONTENT) {
3224            throw new IllegalArgumentException("Only supports 0, WRAP_CONTENT and MATCH_PARENT");
3225        }
3226        mActions.add(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, layoutWidth));
3227    }
  • OverrideTextColorsAction(8.1版本新增)

作用:替换所有TextView中的text文字颜色,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> OverrideTextColorsAction

226    /**
227     * Override all text colors in this layout and replace them by the given text color.
228     *
229     * @param textColor The color to use.
230     *
231     * @hide
232     */
233    public void overrideTextColors(int textColor) {
234        addAction(new OverrideTextColorsAction(textColor));
235    }
  • ReflectionAction(使用最多的)

作用:反射机制设置属性的Action,支持跨进程,在本进程中创建,在另外一个进程中使用(反射调用)。

继承关系:Action -> ReflectionAction

大多数的属性值都是通过这个Action设置的,例如所有的基本类型的数据

3229    /**
3230     * Call a method taking one boolean on a view in the layout for this RemoteViews.
3231     *
3232     * @param viewId The id of the view on which to call the method.
3233     * @param methodName The name of the method to call.
3234     * @param value The value to pass to the method.
3235     */
3236    public void setBoolean(int viewId, String methodName, boolean value) {
3237        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BOOLEAN, value));
3238    }
3239
3240    /**
3241     * Call a method taking one byte on a view in the layout for this RemoteViews.
3242     *
3243     * @param viewId The id of the view on which to call the method.
3244     * @param methodName The name of the method to call.
3245     * @param value The value to pass to the method.
3246     */
3247    public void setByte(int viewId, String methodName, byte value) {
3248        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BYTE, value));
3249    }
3250
3251    /**
3252     * Call a method taking one short on a view in the layout for this RemoteViews.
3253     *
3254     * @param viewId The id of the view on which to call the method.
3255     * @param methodName The name of the method to call.
3256     * @param value The value to pass to the method.
3257     */
3258    public void setShort(int viewId, String methodName, short value) {
3259        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.SHORT, value));
3260    }
3261
3262    /**
3263     * Call a method taking one int on a view in the layout for this RemoteViews.
3264     *
3265     * @param viewId The id of the view on which to call the method.
3266     * @param methodName The name of the method to call.
3267     * @param value The value to pass to the method.
3268     */
3269    public void setInt(int viewId, String methodName, int value) {
3270        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INT, value));
3271    }
3272
3273    /**
3274     * Call a method taking one long on a view in the layout for this RemoteViews.
3275     *
3276     * @param viewId The id of the view on which to call the method.
3277     * @param methodName The name of the method to call.
3278     * @param value The value to pass to the method.
3279     */
3280    public void setLong(int viewId, String methodName, long value) {
3281        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.LONG, value));
3282    }
3283
3284    /**
3285     * Call a method taking one float on a view in the layout for this RemoteViews.
3286     *
3287     * @param viewId The id of the view on which to call the method.
3288     * @param methodName The name of the method to call.
3289     * @param value The value to pass to the method.
3290     */
3291    public void setFloat(int viewId, String methodName, float value) {
3292        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.FLOAT, value));
3293    }
3294
3295    /**
3296     * Call a method taking one double on a view in the layout for this RemoteViews.
3297     *
3298     * @param viewId The id of the view on which to call the method.
3299     * @param methodName The name of the method to call.
3300     * @param value The value to pass to the method.
3301     */
3302    public void setDouble(int viewId, String methodName, double value) {
3303        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.DOUBLE, value));
3304    }
3305
3306    /**
3307     * Call a method taking one char on a view in the layout for this RemoteViews.
3308     *
3309     * @param viewId The id of the view on which to call the method.
3310     * @param methodName The name of the method to call.
3311     * @param value The value to pass to the method.
3312     */
3313    public void setChar(int viewId, String methodName, char value) {
3314        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR, value));
3315    }
3316
3317    /**
3318     * Call a method taking one String on a view in the layout for this RemoteViews.
3319     *
3320     * @param viewId The id of the view on which to call the method.
3321     * @param methodName The name of the method to call.
3322     * @param value The value to pass to the method.
3323     */
3324    public void setString(int viewId, String methodName, String value) {
3325        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.STRING, value));
3326    }
3327
3328    /**
3329     * Call a method taking one CharSequence on a view in the layout for this RemoteViews.
3330     *
3331     * @param viewId The id of the view on which to call the method.
3332     * @param methodName The name of the method to call.
3333     * @param value The value to pass to the method.
3334     */
3335    public void setCharSequence(int viewId, String methodName, CharSequence value) {
3336        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));
3337    }
3338
3339    /**
3340     * Call a method taking one Uri on a view in the layout for this RemoteViews.
3341     *
3342     * @param viewId The id of the view on which to call the method.
3343     * @param methodName The name of the method to call.
3344     * @param value The value to pass to the method.
3345     */
3346    public void setUri(int viewId, String methodName, Uri value) {
3347        if (value != null) {
3348            // Resolve any filesystem path before sending remotely
3349            value = value.getCanonicalUri();
3350            if (StrictMode.vmFileUriExposureEnabled()) {
3351                value.checkFileUriExposed("RemoteViews.setUri()");
3352            }
3353        }
3354        addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
3355    }
  • ReflectionActionWithoutParams:

作用:显示前一个或后一个childVIew,支持跨进程,在本进程中创建,在另外一个进程中使用(反射调用)。

继承关系:Action -> ReflectionActionWithoutParams

例如:showNext和showPrevious

/**
 * Equivalent to calling {@link AdapterViewAnimator#showNext()}
 *
 * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showNext()}
 */
public void showNext(int viewId) {
    addAction(new ReflectionActionWithoutParams(viewId, "showNext"));
}

/**
 * Equivalent to calling {@link AdapterViewAnimator#showPrevious()}
 *
 * @param viewId The id of the view on which to call {@link AdapterViewAnimator#showPrevious()}
 */
public void showPrevious(int viewId) {
    addAction(new ReflectionActionWithoutParams(viewId, "showPrevious"));
}
  • SetDrawableParameters:

作用:Drawable相关参数的设置,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> SetDrawableParameters

/**
 * @hide
 * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
 * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given
 * view.
 * <p>
 * You can omit specific calls by marking their values with null or -1.
 *
 * @param viewId The id of the view that contains the target
 *            {@link Drawable}
 * @param targetBackground If true, apply these parameters to the
 *            {@link Drawable} returned by
 *            {@link android.view.View#getBackground()}. Otherwise, assume
 *            the target view is an {@link ImageView} and apply them to
 *            {@link ImageView#getDrawable()}.
 * @param alpha Specify an alpha value for the drawable, or -1 to leave
 *            unchanged.
 * @param colorFilter Specify a color for a
 *            {@link android.graphics.ColorFilter} for this drawable. This will be ignored if
 *            {@code mode} is {@code null}.
 * @param mode Specify a PorterDuff mode for this drawable, or null to leave
 *            unchanged.
 * @param level Specify the level for the drawable, or -1 to leave
 *            unchanged.
 */
public void setDrawableParameters(int viewId, boolean targetBackground, int alpha,
        int colorFilter, PorterDuff.Mode mode, int level) {
    addAction(new SetDrawableParameters(viewId, targetBackground, alpha,
            colorFilter, mode, level));
}
  • SetEmptyView:

作用:添加一个Empty View,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> SetEmptyView

/**
 * Equivalent to calling {@link AdapterView#setEmptyView(View)}
 *
 * @param viewId The id of the view on which to set the empty view
 * @param emptyViewId The view id of the empty view
 */
public void setEmptyView(int viewId, int emptyViewId) {
    addAction(new SetEmptyView(viewId, emptyViewId));
}
  • SetOnClickFillInIntent:

作用:类似于ListView的onItemListener,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> SetOnClickFillInIntent

/**
 * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
 * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
 * a single PendingIntent template can be set on the collection, see {@link
 * RemoteViews#setPendingIntentTemplate(int, PendingIntent)}, and the individual on-click
 * action of a given item can be distinguished by setting a fillInIntent on that item. The
 * fillInIntent is then combined with the PendingIntent template in order to determine the final
 * intent which will be executed when the item is clicked. This works as follows: any fields
 * which are left blank in the PendingIntent template, but are provided by the fillInIntent
 * will be overwritten, and the resulting PendingIntent will be used. The rest
 * of the PendingIntent template will then be filled in with the associated fields that are
 * set in fillInIntent. See {@link Intent#fillIn(Intent, int)} for more details.
 *
 * @param viewId The id of the view on which to set the fillInIntent
 * @param fillInIntent The intent which will be combined with the parent's PendingIntent
 *        in order to determine the on-click behavior of the view specified by viewId
 */
public void setOnClickFillInIntent(int viewId, Intent fillInIntent) {
    addAction(new SetOnClickFillInIntent(viewId, fillInIntent));
}
  • SetOnClickPendingIntent(常用):

作用:类似于View的onClickListener,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> SetOnClickPendingIntent

例如:SetOnClickPendingIntent

/**
 * Equivalent to calling
 * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
 * to launch the provided {@link PendingIntent}.
 *
 * When setting the on-click action of items within collections (eg. {@link ListView},
 * {@link StackView} etc.), this method will not work. Instead, use {@link
 * RemoteViews#setPendingIntentTemplate(int, PendingIntent)} in conjunction with
 * {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
 *
 * @param viewId The id of the view that will trigger the {@link PendingIntent} when clicked
 * @param pendingIntent The {@link PendingIntent} to send when user clicks
 */
public void setOnClickPendingIntent(int viewId, PendingIntent pendingIntent) {
    addAction(new SetOnClickPendingIntent(viewId, pendingIntent));
}
  • SetPendingIntentTemplate:

作用:类似于ListView的onItemListener,可以根据TAG来发送不同的Intent,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> SetPendingIntentTemplate

例如:SetPendingIntentTemplate

TAG:com.android.internal.R.id.fillInIntent

/**
 * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
 * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
 * this method should be used to set a single PendingIntent template on the collection, and
 * individual items can differentiate their on-click behavior using
 * {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
 *
 * @param viewId The id of the collection who's children will use this PendingIntent template
 *          when clicked
 * @param pendingIntentTemplate The {@link PendingIntent} to be combined with extras specified
 *          by a child of viewId and executed when that child is clicked
 */
public void setPendingIntentTemplate(int viewId, PendingIntent pendingIntentTemplate) {
    addAction(new SetPendingIntentTemplate(viewId, pendingIntentTemplate));
}
  • SetRemoteInputsAction:

作用:支持用户输入操作,支持跨进程,在本进程中创建,在另外一个进程中使用。用户输入完成后通过Intent传回本进程或其他进程。

继承关系:Action -> SetRemoteInputsAction

/**
 * @hide
 */
public void setRemoteInputs(int viewId, RemoteInput[] remoteInputs) {
    mActions.add(new SetRemoteInputsAction(viewId, remoteInputs));
}
  • SetRemoteViewsAdapterIntent:

作用:桌面小控件中存在ListView或GridView时使用,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> SetRemoteViewsAdapterIntent

/**
 * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
 *
 * @param appWidgetId The id of the app widget which contains the specified view. (This
 *      parameter is ignored in this deprecated method)
 * @param viewId The id of the {@link AdapterView}
 * @param intent The intent of the service which will be
 *            providing data to the RemoteViewsAdapter
 * @deprecated This method has been deprecated. See
 *      {@link android.widget.RemoteViews#setRemoteAdapter(int, Intent)}
 */
@Deprecated
public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
    setRemoteAdapter(viewId, intent);
}

/**
 * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
 * Can only be used for App Widgets.
 *
 * @param viewId The id of the {@link AdapterView}
 * @param intent The intent of the service which will be
 *            providing data to the RemoteViewsAdapter
 */
public void setRemoteAdapter(int viewId, Intent intent) {
    addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
}
  • SetRemoteViewsAdapterList:

作用:SetRemoteViewsAdapterIntent的多条功能,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> SetRemoteViewsAdapterList

/**
 * Creates a simple Adapter for the viewId specified. The viewId must point to an AdapterView,
 * ie. {@link ListView}, {@link GridView}, {@link StackView} or {@link AdapterViewAnimator}.
 * This is a simpler but less flexible approach to populating collection widgets. Its use is
 * encouraged for most scenarios, as long as the total memory within the list of RemoteViews
 * is relatively small (ie. doesn't contain large or numerous Bitmaps, see {@link
 * RemoteViews#setImageViewBitmap}). In the case of numerous images, the use of API is still
 * possible by setting image URIs instead of Bitmaps, see {@link RemoteViews#setImageViewUri}.
 *
 * This API is supported in the compatibility library for previous API levels, see
 * RemoteViewsCompat.
 *
 * @param viewId The id of the {@link AdapterView}
 * @param list The list of RemoteViews which will populate the view specified by viewId.
 * @param viewTypeCount The maximum number of unique layout id's used to construct the list of
 *      RemoteViews. This count cannot change during the life-cycle of a given widget, so this
 *      parameter should account for the maximum possible number of types that may appear in the
 *      See {@link Adapter#getViewTypeCount()}.
 *
 * @hide
 */
public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list, int viewTypeCount) {
    addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
}
  • TextViewDrawableAction:

作用:TextView设置Drawable与text距离的方法,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> TextViewDrawableAction

/**
 * Equivalent to calling
 * {@link TextView#setCompoundDrawablesWithIntrinsicBounds(int, int, int, int)}.
 *
 * @param viewId The id of the view whose text should change
 * @param left The id of a drawable to place to the left of the text, or 0
 * @param top The id of a drawable to place above the text, or 0
 * @param right The id of a drawable to place to the right of the text, or 0
 * @param bottom The id of a drawable to place below the text, or 0
 */
public void setTextViewCompoundDrawables(int viewId, int left, int top, int right, int bottom) {
    addAction(new TextViewDrawableAction(viewId, false, left, top, right, bottom));
}

/**
 * Equivalent to calling {@link
 * TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int)}.
 *
 * @param viewId The id of the view whose text should change
 * @param start The id of a drawable to place before the text (relative to the
 * layout direction), or 0
 * @param top The id of a drawable to place above the text, or 0
 * @param end The id of a drawable to place after the text, or 0
 * @param bottom The id of a drawable to place below the text, or 0
 */
public void setTextViewCompoundDrawablesRelative(int viewId, int start, int top, int end, int bottom) {
    addAction(new TextViewDrawableAction(viewId, true, start, top, end, bottom));
}
  • TextViewDrawableColorFilterAction:

作用:设置TextView中Drawable颜色滤镜,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> TextViewDrawableColorFilterAction

/**
 * Equivalent to applying a color filter on one of the drawables in
 * {@link android.widget.TextView#getCompoundDrawablesRelative()}.
 *
 * @param viewId The id of the view whose text should change.
 * @param index  The index of the drawable in the array of
 *               {@link android.widget.TextView#getCompoundDrawablesRelative()} to set the color
 *               filter on. Must be in [0, 3].
 * @param color  The color of the color filter. See
 *               {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
 * @param mode   The mode of the color filter. See
 *               {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
 * @hide
 */
public void setTextViewCompoundDrawablesRelativeColorFilter(int viewId,
        int index, int color, PorterDuff.Mode mode) {
    if (index < 0 || index >= 4) {
        throw new IllegalArgumentException("index must be in range [0, 3].");
    }
    addAction(new TextViewDrawableColorFilterAction(viewId, true, index, color, mode));
}
  • TextViewSizeAction:

作用:设置TextView中text文字大小,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> TextViewSizeAction

/**
 * Equivalent to calling {@link TextView#setTextSize(int, float)}
 *
 * @param viewId The id of the view whose text size should change
 * @param units The units of size (e.g. COMPLEX_UNIT_SP)
 * @param size The size of the text
 */
public void setTextViewTextSize(int viewId, int units, float size) {
    addAction(new TextViewSizeAction(viewId, units, size));
}
  • ViewGroupActionAdd:(8.1增加)

作用:向layout中增加RemoteViews,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> ViewGroupActionAdd

2654    /**
2655     * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the
2656     * given {@link RemoteViews}. This allows users to build "nested"
2657     * {@link RemoteViews}. In cases where consumers of {@link RemoteViews} may
2658     * recycle layouts, use {@link #removeAllViews(int)} to clear any existing
2659     * children.
2660     *
2661     * @param viewId The id of the parent {@link ViewGroup} to add child into.
2662     * @param nestedView {@link RemoteViews} that describes the child.
2663     */
2664    public void addView(int viewId, RemoteViews nestedView) {
2665        addAction(nestedView == null
2666                ? new ViewGroupActionRemove(viewId)
2667                : new ViewGroupActionAdd(viewId, nestedView));
2668    }
2669
2670    /**
2671     * Equivalent to calling {@link ViewGroup#addView(View, int)} after inflating the
2672     * given {@link RemoteViews}.
2673     *
2674     * @param viewId The id of the parent {@link ViewGroup} to add the child into.
2675     * @param nestedView {@link RemoveViews} of the child to add.
2676     * @param index The position at which to add the child.
2677     *
2678     * @hide
2679     */
2680    public void addView(int viewId, RemoteViews nestedView, int index) {
2681        addAction(new ViewGroupActionAdd(viewId, nestedView, index));
2682    }
  • ViewGroupActionRemove:(8.1增加)

作用:向layout中移除View,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> ViewGroupActionRemove

2684    /**
2685     * Equivalent to calling {@link ViewGroup#removeAllViews()}.
2686     *
2687     * @param viewId The id of the parent {@link ViewGroup} to remove all
2688     *            children from.
2689     */
2690    public void removeAllViews(int viewId) {
2691        addAction(new ViewGroupActionRemove(viewId));
2692    }
2693
2694    /**
2695     * Removes all views in the {@link ViewGroup} specified by the {@code viewId} except for any
2696     * child that has the {@code viewIdToKeep} as its id.
2697     *
2698     * @param viewId The id of the parent {@link ViewGroup} to remove children from.
2699     * @param viewIdToKeep The id of a child that should not be removed.
2700     *
2701     * @hide
2702     */
2703    public void removeAllViewsExceptId(int viewId, int viewIdToKeep) {
2704        addAction(new ViewGroupActionRemove(viewId, viewIdToKeep));
2705    }
  • ViewGroupAction:(8.1废除,使用ViewGroupActionRemove和ViewGroupActionAdd代替)

作用:向layout中移除View,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> ViewGroupAction

  • ViewPaddingAction:

作用:设置View的Padding值,支持跨进程,在本进程中创建,在另外一个进程中使用。

继承关系:Action -> ViewPaddingAction

/**
 * Equivalent to calling {@link android.view.View#setPadding(int, int, int, int)}.
 *
 * @param viewId The id of the view to change
 * @param left the left padding in pixels
 * @param top the top padding in pixels
 * @param right the right padding in pixels
 * @param bottom the bottom padding in pixels
 */
public void setViewPadding(int viewId, int left, int top, int right, int bottom) {
    addAction(new ViewPaddingAction(viewId, left, top, right, bottom));
}

4.Action怎么转化为View的流程:

 在系统需要将RemoteViews转化为View时,会调用其隐藏的apply方法,当然APP应用也可以使用反射的方法调用(9.0版本之前)。此时会执行到getRemoteViewsToApply方法中,获取当前需要显示横向的还是纵向的RemoteViews,之后在根据这个RemoteViews生成响应的ViewTree(View树性结构),也就是执行LayoutInflater的infalte方法将对应的布局文件的ID转化为ViewTree,有了ViewTree后就要对每个View进行初始化操作,此时就执行到了performApply方法。在此方法中会遍历所有的Action,并执行其apply方法,这样RemoteViews就转成了我们在UI上看见的画面,并完成了初始化操作。

以ReflectionAction举例具体说明Action的执行过程。在创建ReflectionAction时会初始化其成员变量:viewId、methodName、type和value等值,在apply方法中根据viewId寻找响应的View,根据methodname寻找响应的方法,之后利用反色机制将value值更新到View上,这样此Action就执行完了。

源码如下:

1510        @Override
1511        public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
1512            final View view = root.findViewById(viewId);
1513            if (view == null) return;
1514
1515            Class<?> param = getParameterType();
1516            if (param == null) {
1517                throw new ActionException("bad type: " + this.type);
1518            }
1519
1520            try {
1521                getMethod(view, this.methodName, param).invoke(view, wrapArg(this.value));
1522            } catch (ActionException e) {
1523                throw e;
1524            } catch (Exception ex) {
1525                throw new ActionException(ex);
1526            }
1527        }

5.总结:

  1. RemoteViews是一个支持跨进程创建并更新View的工具类;
  2. RemoteViews是一个学习Parceable跨进程传输数据的工具;
  3. RemoteViews创建View和更新View都是在另一个进程中进行的,在本进程中主要是将Action等数据存储后等待传输到另外一个进程中。

本人浅见,欢迎斧正!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值