Tian haili @ csdn
2012-8-20
This article describes the role of appwidgetprvodier in the entire appwidget system from the perspective of appwidgetprovider development. This article analyzes how appwidgetprovider is identified by the appwidget system, how appwidgetprovider provides and updates data through remoteviews, and how to respond to the pendingintent button provided by remoteviews.
Generally, application developers do not focus on the development of other appwidget components (such as appwidgethost or appwidget internal components). Therefore, appwidgetprovider development is called "appwidget development" directly ".
1. Implement an appwidgetprovider
To implement an appwidgetprovider, you must:
- Implement the subclass of appwidgetprovider, and at least override onupdate () method [not required, but if this is not done, the appwidgetprovider does not provide any content, nor is it appwidgetprovider];
- In androidmanifest. XML, declare that the sub-class of the above appwidgetprovider is a aggreger and:
- The intent-filter action of the attacker must contain "android. appwidget. Action. appwidget_update ";
- The meta-data of the aggreger is "android. appwidget. provider" and uses an XML file to describe the layout attributes.
The node name that describes the layout attribute in the XML file 2.2 must be "appwidget-provider ".
The above points are the marks of the appwidget system to determine whether it is appwidgetprovider. In section 3.2, We will detail how to be retrieved and added to the system.
Ii. appwidgetprovider Class Analysis
Appwidgetprovider is a broadcastreceiver which must be declared in androidmanifest. xml and receive "android. appwidget. Action. appwidget_update ".
The implementation of appwidgetprovider class is a template mode:
Figure 1. appwidgetprovider
The onreceiver () Implementation of appwidgetprovider is connected to the received actionappwidgetmanager. action_appwidget_update/appwidgetmanager. action_appwidget_deleted/appwidgetmanager. action_appwidget_enabled and appwidgetmanager. action_appwidget_disabled is processed and onupdate ()/ondeleted ()/onenabled ()/ondisabled () is executed respectively ().
Therefore, the implementation class of appwidgetprovider must be overrideonreceive () and onxxx () [Note: At least onupdate () must be implemented. Here appwidgetprovider provides content to appwidgethost through remoteviews. Otherwise, the so-called appwidgetprovider does not provide anything].
At the beginning of onreceive (),Execute super. onreceive ()Let appwidgetprovider distribute the preceding broadcast messages to be processed by appwidgetprovider.
Appwidgetprovider processes broadcasts in appwidget:
- Onupdate () processes appwidgetmanager. action_appwidget_update broadcast. This broadcast is sent by appwidgetservice. sendupdateintentlocked () When appwidgetprovider needs to provide remoteviews data.
- Ondeleted () processes appwidgetmanager. action_appwidget_deleted broadcast. The broadcast is sent by appwidgetservice. deleteappwidgetlocked () when the appwidgetprovider instance is deleted.
- Onenabled () processes appwidgetmanager. action_appwidget_enabled broadcast. When the appwidgetprovider is instantiated, the broadcast is sent by appwidgetservice. sendenableintentlocked.
- Ondisabled () processes appwidgetmanager. action_appwidget_disabled broadcast. When the last instance of the appwidgetprovider instance is deleted, the broadcast is sent by appwidgetservice. deleteappwidgetlocked.
Generally, appwidgetprovider must process onupdate (); onenabled () and ondisabled (). ondeleted () can not be processed.
3. How to identify appwidgetprovider by the System
3.1 configure androidmanifest. XML in appwidgetprovider
In Android, the "power control" appwidget is implemented by settingsappwidgetprovider in settings. First, let's look at its androidmanifest. xml.
The following is the description of the appwidgetprovider in settings:
<receiver android:name=".widget.SettingsAppWidgetProvider" android:label="@string/gadget_title"android:exported="true"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.net.wifi.WIFI_STATE_CHANGED"/> <action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" /> <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" /> <action android:name="android.location.PROVIDERS_CHANGED"/> <action android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" /> </intent-filter> <meta-data android:name="android.appwidget.provider"android:resource="@xml/appwidget_info" /> </receiver>
This satisfies the requirements of 1 & 2 in China. In addition, this appwidget must handle settings such as WiFi, Bluetooth, GPS, data synchronization, and brightness, therefore, we need to handle the broadcast notifications when these corresponding settings change.
For 3, the Res/XML/appwidget_info.xml file is required.
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dip" android:minHeight="72dip" android:updatePeriodMillis="0" android:initialLayout="@layout/widget" ></appwidget-provider>
The minimum width minwidth, minimum height minheight, and initial layoutinitiallayout are defined here. Before the appwidgetprovider provides data through remoteviews, appwidgethost will be able to know where to reserve the approximate location for the appwidget;
Updateperiodmillis indicates whether to periodically update the appwidget. If the value is 0, periodic update is not required.
3.2 The information of appwidgetprovider is recognized by the system.
This part is implemented by appwidgetservice.
When an APK containing appwidgetprovider is installed in the system, appwidgetservice listens to the broadcast and processes the corresponding appwidgetprovider:
- When a packet is added (intent. action_package_added or intent. action_external_applications_available), addprovidersforpackagelocked ()/reply () is executed to add or update the appwidgetprovider;
- When a packet is removed (intent. action_package_removed or intent. action_external_applications_unavailable), removeprovidersforpackagelocked () is executed to remove the appwidgetprovider.
Next we will focus on how to add appwidgetprovider and see the implementation of addprovidersforpackagelocked:
void addProvidersForPackageLocked(String pkgName) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.setPackage(pkgName); List<ResolveInfo> broadcastReceivers =mPackageManager.queryBroadcastReceivers(intent, PackageManager.GET_META_DATA); final int N = broadcastReceivers == null ? 0 :broadcastReceivers.size(); for (int i=0; i<N; i++) { ResolveInfo ri = broadcastReceivers.get(i); ActivityInfo ai = ri.activityInfo; if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE)!= 0) { continue; } if (pkgName.equals(ai.packageName)) { addProviderLocked(ri); } } }
- Retrieve all appwidgetmanager. action_appwidget_update schedulers In the added package and put them into broadcastreceivers: List <resolveinfo>; [line #2 ~ 5]
- For each such broadcast, add the list of installed appwidgetprovider to meet the following requirements:
- Not Installed on external memory;
- The package name of the volume er is the same as the package name installed;
- The node name of meta-data must be "appwidget-provider" [parse the XML content pointed to by Android: Resource in meta-data]
When parsing the XML content directed to by Android: Resource in meta-data, which content is configured by appwidgetproviderinfo in frameworks/base/CORE/RES/values/attrs. xml:
<declare-styleable name="AppWidgetProviderInfo"> <!-- Minimum width of the AppWidget. --> <attr name="minWidth"/> <!-- Minimum height of the AppWidget. --> <attr name="minHeight"/> <!-- Update period in milliseconds, or 0 if the AppWidget will updateitself. --> <attr name="updatePeriodMillis" format="integer"/> <!-- A resource id of a layout. --> <attr name="initialLayout" format="reference"/> <!-- A class name in the AppWidget's package to be launched toconfigure. If not supplied, then no activity will be launched. --> <attr name="configure" format="string" /> </declare-styleable>
After these values are parsed, together with the label, icon, and provider constructed by componentname (packagename, classname), they are assigned to appwidgetproviderinfo and recorded in minstalledproviders of appwidgetservice: arraylist <provider>.
Figure 2. appwidgetproviderinfo
Iv. Enable and disable of appwidgetprovider
Because appwidgetprovider only provides the display content, which is displayed in appwidgethost. Because of the relationship between the android mechanism, the background appwidgetprovider is easily killed by the system. Therefore, appwidgetprovider correctly sets onenbaled () and ondisabled () for appwidgetmanager. action_appwidget_enabled and appwidgetmanager. action_appwidget_disabled () when receiving appwidgetmanager.
In onenbaled (), the appwidgetprovider is being used and cannot be killed:
PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting( new ComponentName("com.android.settings",".widget.SettingsAppWidgetProvider"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
In ondisabled (), the appwidgetprovider is no longer used and can be killed:
Class clazz = com.android.settings.widget.SettingsAppWidgetProvider.class; PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting( new ComponentName("com.android.settings",".widget.SettingsAppWidgetProvider"), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
5. content provided by appwidgetprovider through remoteviews
When appwidgetprovider is required to provide remoteviews, The appwidget system sends an appwidgetmanager. action_appwidget_update broadcast, and onupdate () is executed.
Figure 3. appwidgetprovider provides remoteviews
- In onupdate (), create a remoteviews instance and input the package name of appwidgteprovider and the layout used by the appwidget. [seq #5]
- If you want to respond to the click operation of a viewid in layoutid, you need to create a local pendingintent and set it to remoteviews through setonclickpendingintetn; [seq #6 ~ #9]
- Add a display element to the control to be displayed in layoutid, such as the imageresource of an imageview. [Seq #10]
- Appwidgetmanager. updateappwidget () is used to update remoteviews to the system. The appwidget system updates the bound appwidgethost. [Seq #11]
For detailed implementation of remoteviews settings and display, see implementation of remoteviews in Android. For details about how to update remoteview in appwidgethost, see Analysis of appwidget processing by launcher in Android: appwidgethost role.
6. Set button response through pendingintent
As mentioned above, you can set pendingintent for remoteviews to get the response when the view you are interested in is clicked:
Intent launchIntent = new Intent(); launchIntent.setClass(context, SettingsAppWidgetProvider.class); launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE); launchIntent.setData(Uri.parse("custom:" + buttonId)); PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* norequestCode */, launchIntent, 0 /* no flags */);
Buttonid is the custom ID corresponding to each button in layout. This ID can be used in this program to differentiate which button is used and is referred to as the "custom:" parameter.
Appwidgetprovider itself is a broadcastreceiver. In its onreceive (), you can determine which button is clicked:
If (intent. hascategory (intent. category_alternative) {uri data = intent. getdata (); int buttonid = integer. parseint (data. getschemespecificpart (); If (buttonid = button_wifi) {// switch WiFi status} else if (buttonid = button_brightness) {// switch brightness} else if (buttonid = button_sync) {// switch Data Synchronization settings} else if (buttonid = button_gps) {// switch GPS on/off} else if (buttonid = button_bluetooth) {// switch the Bluetooth on status }}
Summary
This article describes:
- Implement the configuration and implementation required by an appwidgetprovider;
- How can appwidgetprovider be identified by appwidgets and added to the installed list;
- How does appwidgetprovider generate a remoteviews object and update it to appwidgethost;
- Appwidgetprovider response button operation.
Articles for further reference
Android appwidget framework
Appwidget system framework.
Select and bind an appwidget in Android
See how to call the list of obtained appwidgetproviders described in this article.
Appwidget Analysis and Application in Android: appwidgetprovider
This article.
Analysis of appwidget processing by launcher in Android: appwidgethost role
You can see how to create and display the graphic elements provided by appwidgetprovider in remoteviews after selecting and binding appwidgetprovider and launcher as appwidgethost. You can also see the data model loading.
Implementation of remoteviews in Android
How to Implement the onclickpendingintent and viewimageresource in remoteviews.