刚学做了个Widget,感觉不错哦,先来秀下效果(用朋友手机截的图)
这个Widget会每隔5秒钟自动切换内容和图片,图片最好使用小图,大图会导致你手机桌面(UI)线程卡顿
教程开始:
1、首先创建一个布局(layout),用以显示Wdiget
activity_main.xml
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/ddz_gameend_frame"
- >
- <!--Relativelayout 的 android:background请自行更换你的图片-->
- <TextView
- android:id="@+id/textview_1"
- android:layout_width="60.0dp"
- android:layout_height="90.0dp"
- android:layout_marginLeft="35.0dp"
- android:layout_marginTop="34.0dp"
- android:textColor="#000000"
- android:text=""
- />
- <ImageView
- android:id="@+id/imageview_1"
- android:layout_width="136.0dp"
- android:layout_height="92.0dp"
- android:layout_toRightOf="@+id/textview_1"
- android:layout_marginLeft="5.0dp"
- android:layout_marginTop="42.0dp"
- />
- <Button
- android:id="@+id/button_1"
- android:layout_width="50.0dp"
- android:layout_height="20.0dp"
- android:layout_below="@+id/textview_1"
- android:layout_marginTop="10.0dp"
- android:layout_marginLeft="35.0dp"
- android:text="详情"
- />
- <!--本人的程序用了android:background="@drawable/mybutton",为了简化示例在此不使用-->
- </RelativeLayout>
2、然后创建一个appwidget-provider 的XML文件,点击资源目录的Res文件夹,鼠标右键选择New- android xml file
mywidget_provider.xml
- <?xml version="1.0" encoding="utf-8"?>
- <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
- android:resizeMode="horizontal"
- android:minWidth="250.0dp"
- android:minHeight="110.0dp"
- android:updatePeriodMillis="86400000"
- android:initialLayout="@layout/activity_main"
- android:widgetCategory="home_screen|keyguard"
- >
- </appwidget-provider>
android:updatePeriodMillis指示了更新间隔,86400000为24小时,也就是一天一次,本程序自己采用后台服务更新,所以该设置其实对本程序来说关系不大。 android:initialLayout就是指向的Widget布局
android:widgetCategory指示该Widget可以用作桌面和锁屏
3、在src目录创建代码文件(本实例建了包 com.feature.test;)
Constant.class (用来定义一些常量的类)
- package com.feature.test;
- public class Constant {
- //更新广播
- public static final String ACTION_UPDATE_ALL="com.feature.test.update_all";
- //intent integer data
- public static final String INTEGER_DATA="integer_data";
- }
MyAppWidgetProvider.class (用来处理Widget更新的类)
- package com.feature.test;
- import java.util.HashSet;
- import java.util.Iterator;
- import android.app.PendingIntent;
- import android.appwidget.AppWidgetManager;
- import android.appwidget.AppWidgetProvider;
- import android.content.Context;
- import android.content.Intent;
- import android.net.Uri;
- import android.util.Log;
- import android.widget.RemoteViews;
- import android.widget.Toast;
- public class MyAppWidgetProvider extends AppWidgetProvider{
- private static final Intent AppWidget_Service=new Intent("com.feature.test.MyAppWidgetService");
- //保存WidgetId HashSet 可能有用户创建了多个Widget
- private static HashSet<Integer> hashSet=new HashSet<Integer>();
- //图片资源,作者请自行修改成自己的图片
- private static final int[] ResId={R.drawable.a1,R.drawable.a2,R.drawable.a3,R.drawable.a4,R.drawable.a5};
- //文本资源
- private static final String[] intro={"神挡杀神,佛挡杀佛","仿佛兮若轻云之蔽月,飘飘兮若流风之回雪",
- "此乃驱狼吐虎之计,敬你之手他一搏吧","汝等小儿,可敢杀我",
- "汝等看好了"};
- private static int iCur=-1;
- //周期更新时调用
- @Override
- public void onUpdate(Context context,AppWidgetManager appWidgetProvider,int[] appWidgetIds)
- {
- Log.v("创建Widget", "OK");
- // 每次 widget 被创建时,对应的将widget的id添加到set中
- for(int id:appWidgetIds)
- hashSet.add(Integer.valueOf(id));
- }
- //当桌面组件删除时调用
- @Override
- public void onDeleted(Context context,int[] appWidgetIds)
- {
- for(int id:appWidgetIds)
- hashSet.remove(id);
- super.onDeleted(context, appWidgetIds);
- }
- //当桌面提供的第一个组件创建时调用
- @Override
- public void onEnabled(Context context)
- {
- //启动服务
- context.startService(AppWidget_Service);
- super.onEnabled(context);
- }
- //当桌面提供的最后一个组件删除时调用
- @Override
- public void onDisabled(Context context)
- {
- //停止服务
- context.stopService(AppWidget_Service);
- super.onDisabled(context);
- }
- /*
- * 重写广播接收方法
- * 用于接收除系统默认的更新广播外的 自定义广播(本程序由服务发送过来的,一个是更新UI,一个是按钮事件消息)
- */
- @Override
- public void onReceive(Context context,Intent intent)
- {
- String getAction=intent.getAction();
- if(getAction.equals(Constant.ACTION_UPDATE_ALL))
- {
- //更新广播
- updateAllWidget(context,AppWidgetManager.getInstance(context), hashSet);
- }
- else if(intent.hasCategory(Intent.CATEGORY_ALTERNATIVE))
- {
- Uri data=intent.getData();
- Log.v("button",data.toString()+" ");
- int buttonid=Integer.parseInt(data.getSchemeSpecificPart());
- Toast.makeText(context, intro[buttonid],Toast.LENGTH_SHORT).show();
- }
- super.onReceive(context, intent);
- }
- //更新UI
- public void updateAllWidget(Context context,AppWidgetManager manager,HashSet<Integer> set)
- {
- int AppId;
- Iterator iterator=set.iterator();
- iCur=iCur+1>=intro.length? 0: iCur+1;
- while(iterator.hasNext())
- {
- AppId=((Integer)iterator.next()).intValue();
- RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.activity_main);
- //设置显示的文字图片
- remoteViews.setTextViewText(R.id.textview_1, intro[iCur]);
- remoteViews.setImageViewResource(R.id.imageview_1, ResId[iCur]);
- //添加按钮事件处理
- remoteViews.setOnClickPendingIntent(R.id.button_1, getPendingIntent(context, iCur));
- //更新
- manager.updateAppWidget(AppId, remoteViews);
- }
- }
- //设置按钮事件处理
- private PendingIntent getPendingIntent(Context context,int buttonid)
- {
- Intent intent=new Intent("test.test");
- intent.setClass(context, MyAppWidgetProvider.class);
- intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
- intent.setData(Uri.parse("custom:"+buttonid));
- //进行广播
- PendingIntent pi=PendingIntent.getBroadcast(context, 0, intent, 0);
- return pi;
- }
- }
4、创建后台服务,用来定时发送广播,通知Widget需要更新了
MyAppWidgetService。class
- package com.feature.test;
- import android.app.Service;
- import android.content.Context;
- import android.content.Intent;
- import android.os.IBinder;
- public class MyAppWidgetService extends Service{
- private Context context;
- //更新周期
- private static final int UPDATE_TIME=5000;
- //周期性更新的Widget 线程
- private WidgetThread widgetThread;
- @Override
- public IBinder onBind(Intent intent) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public void onCreate()
- {
- widgetThread=new WidgetThread();
- widgetThread.start();
- context=this.getApplicationContext();
- super.onCreate();
- }
- @Override
- public void onDestroy()
- {
- if(widgetThread!=null&&widgetThread.isAlive())
- widgetThread.interrupt();
- super.onDestroy();
- }
- private class WidgetThread extends Thread
- {
- @Override
- public void run()
- {
- try
- {
- while(true)
- {
- Intent intent=new Intent(Constant.ACTION_UPDATE_ALL);
- context.sendBroadcast(intent);
- sleep(UPDATE_TIME);
- }
- }catch(InterruptedException error)
- {
- // 将 InterruptedException 定义在while循环之外,意味着抛出 InterruptedException 异常时,终止线程。
- }
- }
- }
- }
5、在AndroidManifest.xml注册Widget和服务
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.feature.test"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Black" >
- <!-- 注册AppWidget Provider -->
- <receiver
- android:name="com.feature.test.MyAppWidgetProvider">
- <meta-data android:name="android.appwidget.provider"
- android:resource="@xml/mywidget_provider"
- />
- <intent-filter >
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
- <action android:name="com.feature.test.update_all" />
- </intent-filter>
- </receiver>
- <!-- 注册服务 -->
- <service android:name=".MyAppWidgetService">
- <intent-filter>
- <action android:name="com.feature.test.MyAppWidgetService"/>
- </intent-filter>
- </service>
- </application>
- </manifest>
至此大功告成!有问题请、意见请回复,本人虚心求教
另外:
1、如果你手机安装了自己做的Widget,在添加-窗口小工具显示不出来,那是因为你把它装到SD卡导致的,请在应用程序里找到自己的Widget将其移至手机存储即可显示
2、如果你安装的Widget放到桌面上,一直在显示“正在加载窗口小工具”,说明该Widget使用了您手机版本不支持的Widget控件,如EditText,使用它就会报错
转载地址:http://blog.youkuaiyun.com/tabactivity/article/details/9923281