Android3.0自带天气例子

Android 3.0正式版API Level 11中加入了一个天气预报例子,下面是manifest.xml中的关键代码,只是少了xml的编码头:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.android.weatherlistwidget">

    <uses-sdk android:minSdkVersion="11" />

    <application android:label="Weather Widget Sample">

         <receiver android:name="WeatherWidgetProvider">

            <intent-filter>

                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

            </intent-filter>

                   <meta-data android:name="android.appwidget.provider"

                    android:resource="@xml/widgetinfo" />

        </receiver>



         <service android:name="WeatherWidgetService"

            android:permission="android.permission.BIND_REMOTEVIEWS"

            android:exported="false" />



         <provider android:name="WeatherDataProvider"

              android:authorities="com.example.android.weatherlistwidget.provider" />

    </application>

</manifest>

这里WeatherDataProvider.java的源码为主要是ContentProvider相关的处理,这里作为appWidget的receiver

  class WeatherDataPoint {

    String city; //城市

    int degrees; //度数



    WeatherDataPoint(String c, int d) {

        city = c;

        degrees = d;

    }

}



 public class WeatherDataProvider extends ContentProvider {

    public static final Uri CONTENT_URI =

        Uri.parse("content://com.example.android.weatherlistwidget.provider");

    public static class Columns {

        public static final String ID = "_id";

        public static final String CITY = "city";

        public static final String TEMPERATURE = "temperature";

    }



     private static final ArrayList<WeatherDataPoint> sData = new ArrayList<WeatherDataPoint>();



    @Override

    public boolean onCreate() {

        sData.add(new WeatherDataPoint("San Francisco", 13));

        sData.add(new WeatherDataPoint("New York", 1));

        sData.add(new WeatherDataPoint("Seattle", 7));

        sData.add(new WeatherDataPoint("Boston", 4));

        sData.add(new WeatherDataPoint("Miami", 22));

        sData.add(new WeatherDataPoint("Toronto", -10));

        sData.add(new WeatherDataPoint("Calgary", -13));

        sData.add(new WeatherDataPoint("Tokyo", 8));

        sData.add(new WeatherDataPoint("Kyoto", 11));

        sData.add(new WeatherDataPoint("London", -1));

        sData.add(new WeatherDataPoint("Nomanisan", 27));

        return true;

    }



    @Override

    public synchronized Cursor query(Uri uri, String[] projection, String selection,

            String[] selectionArgs, String sortOrder) {

        assert(uri.getPathSegments().isEmpty());



         final MatrixCursor c = new MatrixCursor(

                new String[]{ Columns.ID, Columns.CITY, Columns.TEMPERATURE });

        for (int i = 0; i < sData.size(); ++i) {

            final WeatherDataPoint data = sData.get(i);

            c.addRow(new Object[]{ new Integer(i), data.city, new Integer(data.degrees) });

        }

        return c;

    }



    @Override

    public String getType(Uri uri) {

        return "vnd.android.cursor.dir/vnd.weatherlistwidget.citytemperature";

    }



    @Override

    public Uri insert(Uri uri, ContentValues values) {

        return null;

    }



    @Override

    public int delete(Uri uri, String selection, String[] selectionArgs) {

        return 0;

    }



    @Override

    public synchronized int update(Uri uri, ContentValues values, String selection,

            String[] selectionArgs) {

        assert(uri.getPathSegments().size() == 1);



        final int index = Integer.parseInt(uri.getPathSegments().get(0));

        final MatrixCursor c = new MatrixCursor(

                new String[]{ Columns.ID, Columns.CITY, Columns.TEMPERATURE });

        assert(0 <= index && index < sData.size());

        final WeatherDataPoint data = sData.get(index);

        data.degrees = values.getAsInteger(Columns.TEMPERATURE);



         getContext().getContentResolver().notifyChange(uri, null);

        return 1;

    }



}

上面可以看到,对于插入和删除没有做过多的处理,对于天气更新给出了详细的解决方法。

有关 WeatherWidgetProvider.java 主要是appWidget的核心,为provider

class WeatherDataProviderObserver extends ContentObserver { //监控数据库的变化

    private AppWidgetManager mAppWidgetManager;

    private ComponentName mComponentName;



    WeatherDataProviderObserver(AppWidgetManager mgr, ComponentName cn, Handler h) {

        super(h);

        mAppWidgetManager = mgr;

        mComponentName = cn;

    }



    @Override

    public void onChange(boolean selfChange) {

           mAppWidgetManager.notifyAppWidgetViewDataChanged(

                mAppWidgetManager.getAppWidgetIds(mComponentName), R.id.weather_list);

    }

}



 public class WeatherWidgetProvider extends AppWidgetProvider {

    public static String CLICK_ACTION = "com.example.android.weatherlistwidget.CLICK";

    public static String REFRESH_ACTION = "com.example.android.weatherlistwidget.REFRESH";

    public static String EXTRA_CITY_ID = "com.example.android.weatherlistwidget.city";



    private static HandlerThread sWorkerThread;

    private static Handler sWorkerQueue;

    private static WeatherDataProviderObserver sDataObserver;



    public WeatherWidgetProvider() {

         sWorkerThread = new HandlerThread("WeatherWidgetProvider-worker"); //开一个线程,这里用到了HandlerThread

        sWorkerThread.start();

        sWorkerQueue = new Handler(sWorkerThread.getLooper()); //不了解Thread的Looper可以看下这个例子比较简单清晰

    }



    @Override

    public void onEnabled(Context context) { //当appWidget添加到桌面上时

           final ContentResolver r = context.getContentResolver();

        if (sDataObserver == null) {

            final AppWidgetManager mgr = AppWidgetManager.getInstance(context);

            final ComponentName cn = new ComponentName(context, WeatherWidgetProvider.class);

            sDataObserver = new WeatherDataProviderObserver(mgr, cn, sWorkerQueue);

            r.registerContentObserver(WeatherDataProvider.CONTENT_URI, true, sDataObserver); //注册监控数据库变化的回调

        }

    }



    @Override

    public void onReceive(Context ctx, Intent intent) {

        final String action = intent.getAction();

        if (action.equals(REFRESH_ACTION)) { //接收数据库改变的回调广播

               final Context context = ctx;

            sWorkerQueue.removeMessages(0);

            sWorkerQueue.post(new Runnable() {

                @Override

                public void run() {

                    final ContentResolver r = context.getContentResolver();

                    final Cursor c = r.query(WeatherDataProvider.CONTENT_URI, null, null, null,

                            null);

                    final int count = c.getCount();

                    final int maxDegrees = 96;



                    r.unregisterContentObserver(sDataObserver); //首先取消数据库监控

                    for (int i = 0; i < count; ++i) {

                        final Uri uri = ContentUris.withAppendedId(WeatherDataProvider.CONTENT_URI, i);

                        final ContentValues values = new ContentValues();

                        values.put(WeatherDataProvider.Columns.TEMPERATURE,

                                new Random().nextInt(maxDegrees));

                        r.update(uri, values, null, null); //更新数据库记录层

                    }

                    r.registerContentObserver(WeatherDataProvider.CONTENT_URI, true, sDataObserver); //重新设置监视数据库



                    final AppWidgetManager mgr = AppWidgetManager.getInstance(context);

                    final ComponentName cn = new ComponentName(context, WeatherWidgetProvider.class);

                    mgr.notifyAppWidgetViewDataChanged(mgr.getAppWidgetIds(cn), R.id.weather_list); //提示Widget有数据更新并刷新UI

                }

            });

        } else if (action.equals(CLICK_ACTION)) {

             final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,

                    AppWidgetManager.INVALID_APPWIDGET_ID);

            final String city = intent.getStringExtra(EXTRA_CITY_ID);

            final String formatStr = ctx.getResources().getString(R.string.toast_format_string);

            Toast.makeText(ctx, String.format(formatStr, city), Toast.LENGTH_SHORT).show();

        }



        super.onReceive(ctx, intent);

    }



    @Override

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

                 for (int i = 0; i < appWidgetIds.length; ++i) {

                      final Intent intent = new Intent(context, WeatherWidgetService.class);   //当桌面上有多个这个相同的appWidget需要分别处理

            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);

            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

            final RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

            rv.setRemoteAdapter(appWidgetIds[i], R.id.weather_list, intent);



            rv.setEmptyView(R.id.weather_list, R.id.empty_view);



            final Intent onClickIntent = new Intent(context, WeatherWidgetProvider.class);

            onClickIntent.setAction(WeatherWidgetProvider.CLICK_ACTION);

            onClickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);

            onClickIntent.setData(Uri.parse(onClickIntent.toUri(Intent.URI_INTENT_SCHEME)));

            final PendingIntent onClickPendingIntent = PendingIntent.getBroadcast(context, 0,

                    onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);

            rv.setPendingIntentTemplate(R.id.weather_list, onClickPendingIntent);



            final Intent refreshIntent = new Intent(context, WeatherWidgetProvider.class);

            refreshIntent.setAction(WeatherWidgetProvider.REFRESH_ACTION);

            final PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(context, 0,

                    refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);

            rv.setOnClickPendingIntent(R.id.refresh, refreshPendingIntent);



            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);

        }

        super.onUpdate(context, appWidgetManager, appWidgetIds);

    }

}

对于WeatherWidgetService.java这个Service集成于RemoteViewsService,主要是UI上的处理

public class WeatherWidgetService extends RemoteViewsService {

    @Override

    public RemoteViewsFactory onGetViewFactory(Intent intent) {

        return new StackRemoteViewsFactory(this.getApplicationContext(), intent);

    }

}



class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {

    private Context mContext;

    private Cursor mCursor;

    private int mAppWidgetId;



    public StackRemoteViewsFactory(Context context, Intent intent) {

        mContext = context;

        mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,

                AppWidgetManager.INVALID_APPWIDGET_ID);

    }



    public void onCreate() {

    }



    public void onDestroy() {

        if (mCursor != null) {

            mCursor.close();

        }

    }



    public int getCount() {

        return mCursor.getCount();

    }



    public RemoteViews getViewAt(int position) {

        String city = "Unknown City";

        int temp = 0;

        if (mCursor.moveToPosition(position)) {

            final int cityColIndex = mCursor.getColumnIndex(WeatherDataProvider.Columns.CITY);

            final int tempColIndex = mCursor.getColumnIndex(

                    WeatherDataProvider.Columns.TEMPERATURE);

            city = mCursor.getString(cityColIndex);

            temp = mCursor.getInt(tempColIndex);

        }



        final String formatStr = mContext.getResources().getString(R.string.item_format_string);

        final int itemId = (position % 2 == 0 ? R.layout.light_widget_item

                : R.layout.dark_widget_item);

        RemoteViews rv = new RemoteViews(mContext.getPackageName(), itemId);

        rv.setTextViewText(R.id.widget_item, String.format(formatStr, temp, city));



        final Intent fillInIntent = new Intent();

        final Bundle extras = new Bundle();

        extras.putString(WeatherWidgetProvider.EXTRA_CITY_ID, city);

        fillInIntent.putExtras(extras);

        rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);



        return rv;

    }

    public RemoteViews getLoadingView() {

        return null;

    }



    public int getViewTypeCount() {

        return 2;

    }



    public long getItemId(int position) {

        return position;

    }



    public boolean hasStableIds() {

        return true;

    }



    public void onDataSetChanged() {

        if (mCursor != null) {

            mCursor.close();

        }

        mCursor = mContext.getContentResolver().query(WeatherDataProvider.CONTENT_URI, null, null,

                null, null);

    }

}

你可能感兴趣的:(android)