How to Implement Android Desktop Widgets (2)

Posted by chiefrokka on Sun, 07 Jul 2019 03:09:35 +0200

In the last blog, I mainly introduced how to implement an Android desktop widget from the perspective of documentation. This blog will show you how to implement an Android widget with examples!!
Look at the effect map first.

As can be seen from the effect chart, the desktop widget has been implemented, but there is nothing in it. Now let's look at the specific implementation code:

The layout file for the widget:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/text_clock_container">
<TextClock
    android:textAlignment="center"
    android:textSize="48sp"
    android:id="@+id/text_clock"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
</FrameLayout>

The AppWidgetProviderInfo file for the widget:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/app_widget_layout"
    android:minHeight="80dp"
    android:minWidth="80dp"
    android:minResizeHeight="80dp"
    android:minResizeWidth="80dp"
    android:resizeMode="vertical"
    android:widgetCategory="home_screen"
    android:previewImage="@drawable/shape_xxx"
    android:updatePeriodMillis="10000"
    android:configure="com.example.appwidgetdemo.ConfigureActivity">

</appwidget-provider>

Configure Activity files:

package com.example.appwidgetdemo;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by Administrator on 2017/4/21 0021.
 */

public class ConfigureActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("zyq","ConfigureActivity:onCreate");
        setResult(RESULT_OK);
        finish();
    }
}

The implementation file of AppWidgetProvider:

package com.example.appwidgetdemo;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.RemoteViews;

/**
 * Created by Administrator on 2017/4/21 0021.
 */

public class AppWidgetReceiver extends AppWidgetProvider {
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        Log.i("zyq","AppWidgetReceiver:onReceive");

    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        Log.i("zyq","AppWidgetReceiver:onUpdate");
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.app_widget_layout);
        PendingIntent i = PendingIntent.getActivity(context,0,new Intent(context,MainActivity.class),0);
        remoteViews.setOnClickPendingIntent(R.id.text_clock_container,i);
        for (int i1 = 0;i1<appWidgetIds.length;i1++){
            appWidgetManager.updateAppWidget(appWidgetIds[i1], remoteViews);
        }
    }

    @Override
    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
        super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
        Log.i("zyq","AppWidgetReceiver:onAppWidgetOptionsChanged");
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
        Log.i("zyq","AppWidgetReceiver:onDeleted");
    }

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        Log.i("zyq","AppWidgetReceiver:onEnabled");
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
        Log.i("zyq","AppWidgetReceiver:onDisabled");
    }

    @Override
    public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
        super.onRestored(context, oldWidgetIds, newWidgetIds);
        Log.i("zyq","AppWidgetReceiver:onRestored");
    }
}

And registering all files into the manifest files within the system:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.appwidgetdemo">

    <application android:allowBackup="true" android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ConfigureActivity">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
            </intent-filter>
        </activity>
        <receiver android:name=".AppWidgetReceiver">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="android.intent.action.TIME_SET"/>
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/app_widget_provider_info"/>
        </receiver>
    </application>

</manifest>

About the widget implementation code is about so much, here are a few points need to be explained, the first is an attribute previewImage in xml, this attribute must be a drawable, an object defined in xml, can not be a color value, although AS automatically prompt contains the color value, but after the reference, in the The null pointer exception is reported when the widget is actually created, because previewImage does not point to a drawable.
This is perviewImage:

In the onUpdate method in the implementation of AppWidgetProvider, an array of appWidgetIds is introduced. Because the same widget user may create multiple widgets on the desktop, as shown in the effect diagram, the widget needs to be updated according to the ID of the widget, so the same kind of small widget needs to be updated. Parts to update, that is, need to traverse the array!!

Click events are implemented by using pending Intent, which is nothing to say!!!

This is my Wechat Public Number. If you can, I hope you can help me pay attention to it. This will be my greatest encouragement. Thank you!

Code Address: (The code inside is messy, you need to get it yourself according to your needs)
https://github.com/zhuyuqiang2017/Other

Topics: Android xml encoding Attribute