1.概念:
桌面工具(Widget)是Android系统的一大特色,通过桌面工具可以快速得到所需的信息,不必打开程序即可了解最新的内容,就好像是一个应用程序的快捷方式。Android系统自带了一些常用的桌面工具,其他一些经过定制的系统也带有具有特色的桌面工具,同时,有很多第三方程序也支持桌面工具。例如新浪微博提供的AppWidget:
在了解完AppWidget的概念后,我们就要开发一个类似的应用。首先来看个制作的效果:
2.代码部分:
新建个程序,并添加以下代码:
MainActivity.java
<span style="font-size:18px;">package com.example.lxxcaroline.myappwidget; import android.app.Activity; import android.os.Bundle; /** * 主程序入口类 * @author Linxuanxuan */ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }</span>
MyAppWidget.java
<span style="font-size:18px;">package com.example.lxxcaroline.myappwidget; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.widget.RemoteViews; /** * Created by LxxCaroline on 2015/5/2. */ public class MyAppWidget extends AppWidgetProvider { /** * 接收到每个广播时都会被调用,而且在上面的回调函数之前。 * 你通常不需要实现这个方法,因为缺省的AppWidgetProvider实现过滤所有App Widget广播并恰当的调用上述方法。 * 注意: 在Android 1.5中,有一个已知问题,onDeleted()方法在调用时不被调用。 * 为了规避这个问题,你可以像Group post中描述的那样实现onReceive()来接收这个onDeleted()回调。 */ @Override public void onReceive(Context context, Intent intent) { System.out.println("onReceive"); super.onReceive(context, intent); } /** * 用来间隔的更新App Widget,间隔时间用AppWidgetProviderInfo里的updatePeriodMillis属性定义(单位为毫秒)。 * 注意:SDK1.5之后此android:updatePeriodMillis就失效了,要自己创建service更新。 * 这个方法也会在用户添加App Widget时被调用,因此它应该执行基础的设置,比如为视图定义事件处理器并启动一个临时的服务Service,如果需要的话。 * 但是,如果你已经声明了一个配置活动,这个方法在用户添加App Widget时将不会被调用, * 而只在后续更新时被调用。配置活动应该在配置完成时负责执行第一次更新。 * 到达指定的更新时间或者当用户向桌面添加AppWidget时被调用. */ @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { System.out.println("onUpdate"); /** * RemoteViews类描述了一个View对象能够显示在其他进程中,可以融合layout资源文件实现布局。 *虽然该类在android.widget.RemoteViews而不是appWidget下面,但在Android Widgets开发中会经常用到它, *主要是可以跨进程调用(appWidget由一个服务宿主来统一运行的)。 */ RemoteViews myRemoteViews = new RemoteViews(context.getPackageName(), R.layout.my_appwidget_layout); //为RemoteView上的按钮设置点击事件,点击桌面组件时进入主程序入口 Intent intent = new Intent(context, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); myRemoteViews.setOnClickPendingIntent(R.id.contentBtn, pendingIntent); //ComponentName和Intent很相似。 ComponentName myComponentName = new ComponentName(context,MyAppWidget.class); //负责管理AppWidget,向AppwidgetProvider发送通知。提供了更新AppWidget状态,获取已经安装的Appwidget提供信息和其他的相关状态 AppWidgetManager myAppWidgetManager = AppWidgetManager.getInstance(context); myAppWidgetManager.updateAppWidget(myComponentName, myRemoteViews); super.onUpdate(context, appWidgetManager, appWidgetIds); } /** * 当App Widget从宿主中删除时被调用。 删除一个AppWidget时调用 */ @Override public void onDeleted(Context context, int[] appWidgetIds) { System.out.println("onDeleted"); super.onDeleted(context, appWidgetIds); } /** * 当一个App Widget实例第一次创建时被调用。 * 比如,如果用户添加两个App Widget实例,只在第一次被调用。 * 如果你需要打开一个新的数据库或者执行其他对于所有的App Widget实例只需要发生一次的设置,那么这里是完成这个工作的好地方。 */ @Override public void onEnabled(Context context) { System.out.println("onEnabled"); super.onEnabled(context); } @Override public void onDisabled(Context context) { System.out.println("onDisabled"); super.onDisabled(context); } } </span>
res/layout/activity_main.xml:
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="程序入口" /> </LinearLayout></span>
res/layout/my_appwidget_layout.xml:
这里需要注意的是,appwidget的布局文件并不是支持所有的控件,在上述代码中已经看到使用的是RemoteViews,它并不支持所有控件。RemoteViews还用在notification中。
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/background"> <Button android:id="@+id/contentBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="点击进入主程序" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="控件其余内容" android:textSize="20sp" android:layout_gravity="center" android:textColor="#000000"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="控件其余内容" android:textSize="20sp" android:layout_gravity="center" android:textColor="#000000"/> </LinearLayout> </span>
res/xml/my_appwidget.xml:
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?> <!-- AppWidgetProvderInfo: 描述AppWidget的大小、更新频率和初始界面等信息,以XML文件形式存在于应用的res/xml/目录下。 注意:SDK1.5之后此android:updatePeriodMillis就失效了,要自己创建service更新 --> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="150dip" android:minHeight="150dip" android:updatePeriodMillis="1000" android:layout_height="wrap_content" android:layout_width="wrap_content" android:initialLayout="@layout/my_appwidget_layout"/></span>
AndroidManifest.xml:
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.lxxcaroline.myappwidget" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="com.example.lxxcaroline.myappwidget.MainActivity" android:label="主程序"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- MyAppWidget类为一个广播接收器,因为MyAppWidget继承自AppWidgetProvider --> <receiver android:name="com.example.lxxcaroline.myappwidget.MyAppWidget" android:label="添加桌面控件"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/my_appwidget" /> </receiver> </application> <uses-sdk android:minSdkVersion="7" /> </manifest> </span>
项目中用到的图片资源不再说明,读者可以随便贴几张png的图片放在drawable下面。
3.代码说明:
程序正常入口是进入到MainActivity里面去,显示的是activity_main.xml的页面内容。
当点击应用程序图标进入时,MyAppWidget中的代码并不会执行。
接下来为该应用程序创建应用桌面图标,即AppWidget。AppWidget的图样显示是由my_appwidget_layout.xml文件决定。而my_appwidget.xml文件只是说明了该AppWidget应该长什么样,指定AppWidget的布局文件等。
当然最重要的是MyAppWidget里面的代码,他继承自AppWidgetProvider。这个父类中有几个函数,分别是onUpdate()、onDeleted()、onEnabled()、onDisabled()、onReceive()。接下来分别解释这几个函数会在什么时候被执行到。
具体可以看一下两个博客:
http://www.cnblogs.com/qianlifeng/archive/2011/03/26/1996407.html
http://blog.csdn.net/thl789/article/details/7887968