android appwidget笔记
一:实现一个Activity配置widget
(1):在widget配置文件中加入如下代码:
- <span style="white-space:pre"><appwidget-provider
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="250dp"
- android:minHeight="180dp"
- android:updatePeriodMillis="0"
- android:initialLayout="@layout/widget_layout"
- android:resizeMode="vertical"
- android:configure="xx.widgets.ExampleAppWidgetConfigure"
- android:previewImage="@drawable/ic_launcher">
- </appwidget-provider></span>
(2):在Activity中加入如下代码:
- Intent launchIntent = getIntent();
- Bundle extras = launchIntent.getExtras();
- if (extras != null) {
- appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);
- Intent cancelResultValue = new Intent();
- cancelResultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId);
- //未配置完成返回结果
- setResult(RESULT_CANCELED, cancelResultValue);
- } else {
- // only launch if it's for configuration
- // Note: when you launch for debugging, this does prevent this
- // activity from running. We could also turn off the intent
- // filtering for main activity.
- // But, to debug this activity, we can also just comment the
- // following line out.
- finish();
- }
- if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID)
- {
- Intent resultValue = new Intent();
- resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId);
- //配置完成返回结果
- setResult(RESULT_OK, resultValue);
- }
二:如何在RemoteViews中使用ListView
(1):通过RemoteViewsService 渲染器实现
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.content.Intent;
- import android.content.SharedPreferences;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.os.IBinder;
- import android.os.Looper;
- import android.widget.RemoteViews;
- import android.widget.RemoteViewsService;
- public class UpdateService extends RemoteViewsService {
- @Override
- public void onStart(Intent intent, int startId) {
- super.onCreate();
- }
- @Override
- public IBinder onBind(Intent intent) {
- return super.onBind(intent);
- }
- @Override
- public RemoteViewsFactory onGetViewFactory(Intent intent) {
- return new ListRemoteViewsFactory(this.getApplicationContext(), intent);
- }
- class ListRemoteViewsFactory implements
- RemoteViewsService.RemoteViewsFactory {
- private final Context mContext;
- private final List<String> mList;
- public ListRemoteViewsFactory(Context context, Intent intent) {
- mContext = context;
- mList = getDataSources();//获取数据源
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- }
- @Override
- public void onCreate() {
- }
- @Override
- public void onDataSetChanged() {
- }
- @Override
- public void onDestroy() {
- mList.clear();
- }
- @Override
- public int getCount() {
- return mList.size();
- }
- @Override
- public RemoteViews getViewAt(int position) {
- if (position < 0 || position >= mList.size())
- return null;
- String content = mList.get(position);
- final RemoteViews rv = new RemoteViews(mContext.getPackageName(),
- R.layout.row);
- Intent intent = new Intent();
- // TODO
- // intent.setComponent(new ComponentName("包名", "类名"));
- // 与CustomWidget中remoteViews.setPendingIntentTemplate配对使用实现ListView中的Item的点击事件
- rv.setOnClickFillInIntent(R.id.widget_list_item_layout, intent);
- rv.setTextViewText(android.R.id.text1, content);
- return rv;
- }
- @Override
- public RemoteViews getLoadingView() {
- return null;
- }
- @Override
- public int getViewTypeCount() {
- return 1;
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public boolean hasStableIds() {
- return true;
- }
- }
- public List<String>getDataSources() {
- List<String> list = new ArrayList<String>();
- ......
- return list;
- }
- }
(2):在widget的onUpdate中添加代码:
- for (int i = 0; i < appWidgetIds.length; i++) {//如果使用循环,当调试重新运行程序或者重启机器时widget点击事情会失灵
- Intent intent = new Intent(ctxt, WidgetService.class);
- RemoteViews widget = new RemoteViews(ctxt.getPackageName(),
- R.layout.widget);
- widget.setRemoteAdapter(appWidgetIds[i], R.id.words, intent);
- Intent clickIntent = new Intent(ctxt, LoremActivity.class);
- PendingIntent clickPI = PendingIntent.getActivity(ctxt, 0,
- clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- widget.setPendingIntentTemplate(R.id.words, clickPI);//配合getViewAt方法中的setOnClickFillInIntent实现listView中Item的点击事件
- appWidgetManager.updateAppWidget(appWidgetIds[i], widget);
- }
(3):widget.xml
- <?xml version="1.0" encoding="utf-8"?>
- <ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/words"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="3dp"
- android:layout_marginLeft="3dp"
- android:background="@drawable/widget_frame"
- />
(4):row.xml
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:gravity="center_vertical"
- android:paddingLeft="6dip"
- android:minHeight="?android:attr/listPreferredItemHeight"
- />
三:如何更新widget
(1):定时更新
在widget配置文件中有这句 android:updatePeriodMillis="0",这种更新方式已经不能使用了,一般定时更新使用AlarmManager,如下代码
- private void setAlarm(Context context, int appWidgetId, int updateRateSeconds) {
- Intent widgetUpdate = new Intent();
- widgetUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
- widgetUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { appWidgetId });
- // make this pending intent unique by adding a scheme to it
- widgetUpdate.setData(Uri.withAppendedPath(Uri.parse(ImagesWidgetProvider.URI_SCHEME + "://widget/id/"), String.valueOf(appWidgetId)));
- PendingIntent newPending = PendingIntent.getBroadcast(context, 0, widgetUpdate, PendingIntent.FLAG_UPDATE_CURRENT);
- // schedule the updating
- AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- if (updateRateSeconds >= 0) {
- alarms.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), updateRateSeconds * 1000, newPending);
- } else {
- alarms.cancel(newPending);
- }
- }
(2):事件更新,不通过时间更新widget一般使用广播来更新
- public void onReceive(Context context, Intent intent) {
- // TODO Auto-generated method stub
- if (intent.getAction().equals(
- "com.example.widgettestone.WIDGET_CONTROL")) {
- AppWidgetManager manager = AppWidgetManager.getInstance(context);
- ComponentName thisWidget = new ComponentName(context, TaskPad.class);
- int[] appWidgetIds = manager.getAppWidgetIds(thisWidget);
- manager.notifyAppWidgetViewDataChanged(appWidgetIds,R.id.widget_list);//通知RemoteViews刷新数据,在渲染器中重写onDataSetChanged方法重写获取数据源
- } else {
- super.onReceive(context, intent);
- }
- }
AndroidManifest.xml中widget的配置中添加:
- <action android:name="com.example.widgettestone.WIDGET_CONTROL" />
当需要更新的时候发出该广播即可更新:
- Intent intentUpdate = new Intent("com.example.widgettestone.WIDGET_CONTROL");
- pan style="white-space:pre"> </span>context.sendBroadcast(intentUpdate);
四:小问题:
(1):ListView的getview()中重复调用(position重复调用)问题:
网友提供的解决方法:
- 重写的listview adapter中,在getView()方法中,打印语句时,相同的position打印了多次,修改方法:
- 将布局文件中ListView的高度改为“fill_parent”
- <ListView
- android:id="@+id/dynamic_list"
- android:layout_height="fill_parent"
- android:layout_width="fill_parent"
- android:scrollbars="vertical"
- android:layout_weight="1"
- android:drawSelectorOnTop="false"
- android:fadingEdgeLength="0dip"
- android:divider="@null"
- android:dividerHeight="0dip"
- android:cacheColorHint="#00000000"
- android:background="@color/listview_bg_color" />