widget的进一步使用,利用AppWidgetProvider实现桌面的时钟挂件
1、通过上面介绍widget的基本应用外面知道,系统最多30分钟才更新挂件的内容,为了实时更新时钟我们必须自己发送广播来实现挂件内容的更新,其方法就是覆写父类AppWidgetProvider的onReceive()方法,并在注册的广播接收的intent-fliter里添加接受自己的广播。
2、用过查看Mainfest文件知道广播接受原始只注册了android.appwidget.action.APPWIDGET_UPDATE,但是可以接收android.appwidget.action.APPWIDGET_ENABLED,android.appwidget.action.APPWIDGET_DISENABLED,猜想AppWidgetProvider里的接受者在系统里已经注册了接收这些广播,而我写的类继承它,因此也可以接收。
3、当我去掉注册的android.appwidget.action.APPWIDGET_UPDATE只保留我自己添加的更新时间的广播时候却收不到android.appwidget.action.APPWIDGET_UPDATE等一些广播了并且在widget里找不到我定义的挂件了。猜想在系统定义了相应的规则,必须注册了的广播中含有android.appwidget.action.APPWIDGET_UPDATE,且注册的类必须继承了AppWidgetProvider才会在系统里注册一个挂件,并且继承的类可以收到AppWidgetProvider接受的广播。
4、 当我们在存储widgetId时候数据不加static时候发现每次接收到信号时候widgetIds这个集合的size都为0,表明每次接受到广播后就重新创建了NewAppWidge这个类对象。因此在广播类中重要的数据得用static变量。
5 广播机制:广播在mainfest里注册后,当接受到相应的广播后就会创建相应注册在receiver的类,然后由这些类的onreceiver来处理,处理后当系统内存不足的时候就会回收这个对象,然后下次收到的时候就会再次重新创建对象。
下面给出实现的demo:
widget类:
package com.example.user.appwidget; 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.widget.RemoteViews; import android.widget.TextView; import java.util.ArrayList; import java.util.Calendar; import java.util.Comparator; /** * Implementation of App Widget functionality. */ public class NewAppWidget extends AppWidgetProvider { private final static String Action_UpDateTime ="android.appwidget.action.APPWIDGET_UPDATE"; private final static String Action_Enable ="android.appwidget.action.APPWIDGET_ENABLED"; private static ArrayList<Integer> widgetIds = new ArrayList<>(); private static boolean HasUpdateThread = false; Thread upWidget= null; @Override public void onReceive(Context context, Intent intent) { int size = widgetIds.size(); int [] widgetIdArray = new int [size]; for(int i = 0 ; i < size ; i++) { widgetIdArray[i] = widgetIds.get(i); } onUpdate(context , AppWidgetManager.getInstance(context) , widgetIdArray ); System.out.println("收到了广播" + intent.getAction()); super.onReceive(context, intent); } static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { Calendar c = Calendar.getInstance(); int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); int seconds = c.get(Calendar.SECOND); CharSequence widgetText = "Time:" + hour + ":" + minute + ":" + seconds;//context.getString(R.string.appwidget_text); // Construct the RemoteViews object RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget); views.setTextViewText(R.id.appwidget_text, widgetText); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId, views); } // 到达指定更新时间(new_app_widget_info.xml中指定的,大于30分钟才有效,小于30分钟会30分钟执行一次) // 或者向桌面添加Widget时候执行 @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); if(!widgetIds.contains((Integer)appWidgetId)) { System.out.println("不含有挂件"+appWidgetId); widgetIds.add((Integer) appWidgetId); } else System.out.println("含有挂件"+appWidgetId); } if (!HasUpdateThread) { System.out.println("创建了一个进程");HasUpdateThread =true; upWidget = new UpDateWiget(context); upWidget.start(); } } //当第一个widget创建时候执行 @Override public void onEnabled(Context context) { // Enter relevant functionality for when the first widget is created // System.out.println("1111111111111111111111111111111111111111111111"); } //当最后一个widget实例被删除时执行 @Override public void onDisabled(Context context) { // Enter relevant functionality for when the last widget is disabled } class UpDateWiget extends Thread { // public int widgetId; public Context context; public UpDateWiget(Context context) { // this.widgetId = widgetId; this.context = context; } @Override public void run() { while (true) { Intent intent = new Intent("android.appwidget.action.APPWIDGET_UPDATETIME"); // intent.putExtra("wigetId", widgetId); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发送了一条广播"); context.sendBroadcast(intent); } } } }
挂件的布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#09C" android:padding="@dimen/widget_margin"> <TextView android:id="@+id/appwidget_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_margin="8dp" android:background="#09C" android:contentDescription="@string/appwidget_text" android:text="ca" android:textColor="#ffffff" android:textSize="20dp" android:textStyle="bold|italic" /> </RelativeLayout>
mainfset里注册的广播:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.user.appwidget"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" 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> <receiver android:name=".NewAppWidget"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATETIME"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/new_app_widget_info" /> </receiver> </application> </manifest>