Android 2.2新增Widget之ProtipWidget源码

一开始,对widget一点不懂,自学了很长时间,才刚刚入门,这是在网上找的资料,觉得很好,分享给大家
[url]
http://www.android123.com.cn/yuanmaxiazai/564.html
[/url]

在Android 2.2 SDK中我们可能首次启动模拟器可以看到和以前不一样的是多出了一个绿色的小机器人提示信息,Google给我们了演示了Android中如何通过RemoteView和简单的图片轮换方式实现动画效果在桌面小工具中,appWidget的基类时AppWidgetProvider类,不过Widget本身的生命周期管理并非Activity,相对于的而是BroadcastReceiver广播方式处理的,Android 2.2新增的Widget的实现大家可以从中学习到很多有用的知识。

public class ProtipWidget extends AppWidgetProvider {
    public static final String ACTION_NEXT_TIP = "com.android.misterwidget.NEXT_TIP"; //定义action切换到下一条提示
    public static final String ACTION_POKE = "com.android.misterwidget.HEE_HEE"; //唤醒小机器人

    public static final String EXTRA_TIMES = "times";

    public static final String PREFS_NAME = "Protips";
    public static final String PREFS_TIP_NUMBER = "widget_tip";

    private static Random sRNG = new Random(); //轮换图片用到的,生成一个静态的随机数生成器

    private static final Pattern sNewlineRegex = Pattern.compile(" *\\n *");
    private static final Pattern sDrawableRegex = Pattern.compile(" *@(drawable/[a-z0-9_]+) *");   

    // 初始化时Droid是眼睛没有睁开,同时没有信息提示
    private int mIconRes = R.drawable.droidman_open;
    private int mMessage = 0;

    private AppWidgetManager mWidgetManager = null;
    private int[] mWidgetIds;
    private Context mContext;

    private CharSequence[] mTips;

    private void setup(Context context) {
        mContext = context;
        mWidgetManager = AppWidgetManager.getInstance(context);
        mWidgetIds = mWidgetManager.getAppWidgetIds(new ComponentName(context, ProtipWidget.class));

        SharedPreferences pref = context.getSharedPreferences(PREFS_NAME, 0);
        mMessage = pref.getInt(PREFS_TIP_NUMBER, 0);

        mTips = context.getResources().getTextArray(R.array.tips);

        if (mTips != null) {
            if (mMessage >= mTips.length) mMessage = 0;
        } else {
            mMessage = -1;
        }

    }

    public void goodmorning() {  //Android开发网提示线程中轮换图片,使用了500,200,100等这样的0.5秒休眠,0.2秒休眠实现了动画的间隔效果
        mMessage = -1;
        try {
            setIcon(R.drawable.droidman_down_closed);
            Thread.sleep(500);
            setIcon(R.drawable.droidman_down_open);
            Thread.sleep(200);
            setIcon(R.drawable.droidman_down_closed);
            Thread.sleep(100);
            setIcon(R.drawable.droidman_down_open);
            Thread.sleep(600);
        } catch (InterruptedException ex) {
        }
        mMessage = 0;
        mIconRes = R.drawable.droidman_open;
        refresh();
    }

    @Override
    public void onReceive(Context context, Intent intent) { //上面android123已经讲到了,appWidget是基于broadcastreceiver类的,所以说需要响应onReceive通过action来驱动事件。
        setup(context);

        if (intent.getAction().equals(ACTION_NEXT_TIP)) {
            mMessage = getNextMessageIndex();
            SharedPreferences.Editor pref = context.getSharedPreferences(PREFS_NAME, 0).edit();
            pref.putInt(PREFS_TIP_NUMBER, mMessage);
            pref.commit();
            refresh();
        } else if (intent.getAction().equals(ACTION_POKE)) {
            blink(intent.getIntExtra(EXTRA_TIMES, 1));
        } else if (intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
            goodmorning();
        } else {
            mIconRes = R.drawable.droidman_open;
            refresh();
        }
    }

    private void refresh() {  //管理如果有多个本widget执行需要逐个更新
        RemoteViews rv = buildUpdate(mContext);
        for (int i : mWidgetIds) {
            mWidgetManager.updateAppWidget(i, rv);
        }
    }

    private void setIcon(int resId) {
        mIconRes = resId;
        refresh();
    }

    private int getNextMessageIndex() {
        return (mMessage + 1) % mTips.length;
    }

    private void blink(int blinks) {
            if (mMessage < 0) return;

     //Android123提示大家比较有意思的就是小绿人眼睛的一开一闭,这里使用的是图片轮换方式来实现动画效果,在appWidget中我们可以用的控件十分少

        setIcon(R.drawable.droidman_closed); 
        try {
            Thread.sleep(100);
            while (0<--blinks) {
                setIcon(R.drawable.droidman_open);
                Thread.sleep(200);
                setIcon(R.drawable.droidman_closed);
                Thread.sleep(100);
            }
        } catch (InterruptedException ex) { }
        setIcon(R.drawable.droidman_open);
    }

    public RemoteViews buildUpdate(Context context) {
        RemoteViews updateViews = new RemoteViews(
            context.getPackageName(), R.layout.widget); //映射布局,widget.xml文件的源码在下面可以找到

        // 按下bubble的事件,对应action_next_tip动作
        Intent bcast = new Intent(context, ProtipWidget.class);
        bcast.setAction(ACTION_NEXT_TIP);
        PendingIntent pending = PendingIntent.getBroadcast(
            context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
        updateViews.setOnClickPendingIntent(R.id.tip_bubble, pending);

       //这里为action_poke
        bcast = new Intent(context, ProtipWidget.class);
        bcast.setAction(ACTION_POKE);
        bcast.putExtra(EXTRA_TIMES, 1);
        pending = PendingIntent.getBroadcast(
            context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
        updateViews.setOnClickPendingIntent(R.id.bugdroid, pending);

        // Tip bubble text
        if (mMessage >= 0) {
            String[] parts = sNewlineRegex.split(mTips[mMessage], 2);
            String title = parts[0];
            String text = parts.length > 1 ? parts[1] : "";

            // Look for a callout graphic referenced in the text
            Matcher m = sDrawableRegex.matcher(text);
            if (m.find()) {
                String imageName = m.group(1);
                int resId = context.getResources().getIdentifier(

                    imageName, null, context.getPackageName());
                updateViews.setImageViewResource(R.id.tip_callout, resId);
                updateViews.setViewVisibility(R.id.tip_callout, View.VISIBLE);
                text = m.replaceFirst("");
            } else {
                updateViews.setImageViewResource(R.id.tip_callout, 0);
                updateViews.setViewVisibility(R.id.tip_callout, View.GONE);
            }

            updateViews.setTextViewText(R.id.tip_message, 
                text);
            updateViews.setTextViewText(R.id.tip_header,
                title);
            updateViews.setTextViewText(R.id.tip_footer, 
                context.getResources().getString(
                    R.string.pager_footer,
                    (1+mMessage), mTips.length));
            updateViews.setViewVisibility(R.id.tip_bubble, View.VISIBLE);
        } else {
            updateViews.setViewVisibility(R.id.tip_bubble, View.INVISIBLE);
        }

        updateViews.setImageViewResource(R.id.bugdroid, mIconRes);

        return updateViews;
    }
}

有关AndroidManifest.xml中详细的recevier代码如下
<receiver android:name=".ProtipWidget" android:label="@string/widget_name">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="com.android.protips.NEXT_TIP" />
                <action android:name="com.android.protips.HEE_HEE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_build" />
        </receiver>

有关res/xml/widget_build.xml的代码如下

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="294dip"
    android:minHeight="72dip"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/widget" />

有关res/layout/widget.xml的代码如下,注意下面使用了布局文件套嵌的include方式

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="5dip"
    >

    <include layout="@layout/droid" />
    <include layout="@layout/bubble" />
</RelativeLayout>


有关res/layout/droid.xml的代码如下

 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bugdroid"
    android:src="@drawable/droidman_down_closed"
    android:scaleType="center"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true"
    />


有关res/layout/bubble.xml的代码如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tip_bubble"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_toLeftOf="@+id/bugdroid"
    android:layout_centerVertical="true"
    android:gravity="center_vertical|left"
    android:layout_marginRight="2dip"
    android:visibility="invisible"
    android:background="@drawable/droid_widget"
    android:focusable="true"
    >
    <TextView
        android:layout_width="0dip"
        android:layout_height="0dip"
        android:layout_alignParentTop="true"
        android:layout_marginTop="-100dip"
        android:text="@string/widget_name"
        />
    <TextView
        android:layout_width="0dip"
        android:layout_height="0dip"
        android:layout_alignParentTop="true"
        android:layout_marginTop="-90dip"
        android:text="@string/tts_pause"
        />
    <TextView
        android:id="@+id/tip_footer"
        style="@style/TipText.Footer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginRight="1dip"
        />
    <ImageView
        android:id="@+id/tip_callout"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_above="@id/tip_footer"
        android:visibility="gone"
        android:padding="4dip"
        />
    <TextView
        android:id="@+id/tip_header"
        style="@style/TipText.Header"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toLeftOf="@id/tip_callout"
        android:layout_alignWithParentIfMissing="true"
        android:layout_marginTop="0dip"
        android:layout_marginLeft="3dip"
        />
    <TextView
        android:id="@+id/tip_message"
        style="@style/TipText.Message"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tip_header"
        android:layout_alignLeft="@id/tip_header"
        android:layout_alignRight="@id/tip_header"
        android:layout_marginTop="1dip"
        />
</RelativeLayout>


有关上面bubble.xml中的drawable对象droid_widget的代码如下

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/droid_widget_pressed" />
    <item android:state_focused="true" android:state_window_focused="true" android:drawable="@drawable/droid_widget_focused" />
    <item android:state_focused="true" android:state_window_focused="false" android:drawable="@drawable/droid_widget_normal" />
    <item android:drawable="@drawable/droid_widget_normal" />
</selector>

你可能感兴趣的:(thread,多线程,android,xml,Google)