Mobile Development 17 min read

Unlocking Android RemoteViews: Build and Control Widgets & Notifications

This article explains what RemoteViews are, their use cases in notification bars and home‑screen widgets, provides step‑by‑step code for both scenarios, details PendingIntent handling, and dives deep into the internal cross‑process mechanisms that power RemoteViews updates.

AI Code to Success
AI Code to Success
AI Code to Success
Unlocking Android RemoteViews: Build and Control Widgets & Notifications

RemoteViews represents a view hierarchy that can be displayed in another process; it inflates a layout resource and offers basic operations to modify the inflated view tree.

Application Scenarios

Notification bar

Home‑screen widgets

Using RemoteViews in a Notification

Notification notification = new Notification();
notification.icon = R.mipmap.ic_launcher;
notification.tickerText = "hello notification";
notification.when = System.currentTimeMillis();
notification.flags = Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(this, RemoteViewsActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notification);
remoteViews.setTextViewText(R.id.tv, "RemoteViews applied to notification");
remoteViews.setTextColor(R.id.tv, Color.parseColor("#abcdef"));
remoteViews.setImageViewResource(R.id.iv, R.mipmap.ic_launcher);
PendingIntent openActivity2Pending = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.tv, openActivity2Pending);
notification.contentView = remoteViews;
notification.contentIntent = pendingIntent;
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(2, notification);

Using RemoteViews in a Widget

Widgets are implemented via AppWidgetProvider, which extends BroadcastReceiver. The development steps are:

Define the widget layout in an XML file (e.g., widget.xml) containing supported views such as ImageView, TextView, etc.

Define widget configuration in res/xml/appwidget_provider_info.xml specifying android:initialLayout, size, update period, etc.

Implement the provider class (e.g., ImgAppWidgetProvider) that handles onReceive, onUpdate, and a helper updateView method to randomly change an image and set click actions using PendingIntent.

public class ImgAppWidgetProvider extends AppWidgetProvider {
    public static final String TAG = "ImgAppWidgetProvider";
    public static final String CLICK_ACTION = "packagename.action.click";
    private static int index;

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        if (intent.getAction().equals(CLICK_ACTION)) {
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
            updateView(context, remoteViews, appWidgetManager);
        }
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
        updateView(context, remoteViews, appWidgetManager);
    }

    public void updateView(Context context, RemoteViews remoteViews, AppWidgetManager appWidgetManager) {
        index = (int) (Math.random() * 3);
        if (index == 1) {
            remoteViews.setImageViewResource(R.id.iv, R.mipmap.haimei1);
        } else if (index == 2) {
            remoteViews.setImageViewResource(R.id.iv, R.mipmap.haimei2);
        } else {
            remoteViews.setImageViewResource(R.id.iv, R.mipmap.haimei3);
        }
        Intent clickIntent = new Intent();
        clickIntent.setAction(CLICK_ACTION);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, clickIntent, 0);
        remoteViews.setOnClickPendingIntent(R.id.iv, pendingIntent);
        appWidgetManager.updateAppWidget(new ComponentName(context, ImgAppWidgetProvider.class), remoteViews);
    }
}

The widget must be declared in AndroidManifest.xml as a <receiver> with appropriate <intent-filter> entries for the click action and APPWIDGET_UPDATE.

Widget Lifecycle Callbacks

onEnable

: called when the first instance of the widget is added. onUpdate: called on each scheduled update or when the widget is added. onDelete: called each time a widget instance is removed. onDisable: called when the last instance is removed. onReceive: base broadcast handling; custom actions should call super.onReceive first.

PendingIntent Overview

PendingIntent represents an intent that will be executed later. It supports three types: getActivity(...) – starts an activity. getService(...) – starts a service. getBroadcast(...) – sends a broadcast.

Common flag values: FLAG_ONE_SHOT – can be used only once. FLAG_NO_CREATE – returns null if the PendingIntent does not already exist. FLAG_CANCEL_CURRENT – cancels existing PendingIntent before creating a new one. FLAG_UPDATE_CURRENT – updates the extras of an existing PendingIntent.

Internal Mechanism of RemoteViews

RemoteViews does not expose findViewById; instead it records actions (e.g., ReflectionAction) via methods like setTextViewText. These actions are stored in a list and later applied in the remote process.

public void setTextViewText(int viewId, CharSequence text) {
    setCharSequence(viewId, "setText", text);
}

private void setCharSequence(int viewId, String methodName, CharSequence value) {
    addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));
}

When a notification containing a RemoteViews is posted, the flow is: NotificationManager.notify(...) forwards to INotificationManager.enqueueNotificationWithTag (AIDL).

The system service NotificationManagerService creates a NotificationRecord and posts a EnqueueNotificationRunnable to a handler.

The runnable eventually posts a PostNotificationRunnable, which calls buzzBeepBlinkLocked to handle sound, vibration, and LED effects.

Finally, StatusBarManagerInternal.buzzBeepBlinked() triggers the status bar to render the notification.

The key point is that RemoteViews actions are serialized as Parcelable objects, transferred via Binder to the SystemServer process, where they are applied to the inflated layout, avoiding the need for a large set of custom AIDL interfaces.

Significance of RemoteViews

RemoteViews enables cross‑process UI updates, making it suitable when an app needs to frequently update another app’s UI (e.g., notifications or widgets) without the overhead of custom AIDL communication, provided the UI uses supported view types.

JavaAndroidWidgetsNotificationsPendingIntentRemoteViews
AI Code to Success
Written by

AI Code to Success

Focused on hardcore practical AI technologies (OpenClaw, ClaudeCode, LLMs, etc.) and HarmonyOS development. No hype—just real-world tips, pitfall chronicles, and productivity tools. Follow to transform workflows with code.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.