android 桌面小工具(Widget)开发教程

刚学做了个Widget,感觉不错哦,先来秀下效果(用朋友手机截的图)

这个Widget会每隔5秒钟自动切换内容和图片,图片最好使用小图,大图会导致你手机桌面(UI)线程卡顿


教程开始:

1、首先创建一个布局(layout),用以显示Wdiget

activity_main.xml

[java]  view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="wrap_content"  
  3.     android:layout_height="wrap_content"  
  4.     android:background="@drawable/ddz_gameend_frame"              
  5.     >  
  6.    <!--Relativelayout 的 android:background请自行更换你的图片-->  
  7.    <TextView   
  8.         android:id="@+id/textview_1"  
  9.         android:layout_width="60.0dp"  
  10.         android:layout_height="90.0dp"  
  11.         android:layout_marginLeft="35.0dp"  
  12.         android:layout_marginTop="34.0dp"  
  13.         android:textColor="#000000"  
  14.         android:text=""  
  15.         />  
  16.     <ImageView  
  17.         android:id="@+id/imageview_1"  
  18.         android:layout_width="136.0dp"  
  19.         android:layout_height="92.0dp"  
  20.         android:layout_toRightOf="@+id/textview_1"  
  21.         android:layout_marginLeft="5.0dp"  
  22.         android:layout_marginTop="42.0dp"  
  23.         />  
  24.     <Button   
  25.         android:id="@+id/button_1"  
  26.         android:layout_width="50.0dp"  
  27.         android:layout_height="20.0dp"  
  28.         android:layout_below="@+id/textview_1"  
  29.         android:layout_marginTop="10.0dp"  
  30.         android:layout_marginLeft="35.0dp"  
  31.         android:text="详情"          
  32.         />  
  33.      <!--本人的程序用了android:background="@drawable/mybutton",为了简化示例在此不使用-->  
  34.  </RelativeLayout>  

2、然后创建一个appwidget-provider 的XML文件,点击资源目录的Res文件夹,鼠标右键选择New- android xml file

mywidget_provider.xml

[java]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:resizeMode="horizontal"  
  4.     android:minWidth="250.0dp"  
  5.     android:minHeight="110.0dp"  
  6.     android:updatePeriodMillis="86400000"  
  7.     android:initialLayout="@layout/activity_main"  
  8.     android:widgetCategory="home_screen|keyguard"  
  9.     >  
  10. </appwidget-provider>  

android:updatePeriodMillis指示了更新间隔,8640000024小时,也就是一天一次,本程序自己采用后台服务更新,所以该设置其实对本程序来说关系不大。 android:initialLayout就是指向的Widget布局
android:widgetCategory指示该Widget可以用作桌面和锁屏


3、在src目录创建代码文件(本实例建了包  com.feature.test;)

Constant.class   (用来定义一些常量的类)

[java]  view plain copy
  1. package com.feature.test;  
  2.   
  3. public class Constant {  
  4.   
  5.     //更新广播  
  6.     public static final String ACTION_UPDATE_ALL="com.feature.test.update_all";  
  7.       
  8.     //intent integer data  
  9.     public static final String INTEGER_DATA="integer_data";  
  10. }  



MyAppWidgetProvider.class    (用来处理Widget更新的类)

[java]  view plain copy
  1. package com.feature.test;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Iterator;  
  5.   
  6. import android.app.PendingIntent;  
  7. import android.appwidget.AppWidgetManager;  
  8. import android.appwidget.AppWidgetProvider;  
  9. import android.content.Context;  
  10. import android.content.Intent;  
  11. import android.net.Uri;  
  12. import android.util.Log;  
  13. import android.widget.RemoteViews;  
  14. import android.widget.Toast;  
  15.   
  16. public class MyAppWidgetProvider extends AppWidgetProvider{  
  17.   
  18.     private static final Intent AppWidget_Service=new Intent("com.feature.test.MyAppWidgetService");  
  19.       
  20.     //保存WidgetId HashSet  可能有用户创建了多个Widget  
  21.     private static HashSet<Integer> hashSet=new HashSet<Integer>();  
  22.     //图片资源,作者请自行修改成自己的图片  
  23.     private static final int[] ResId={R.drawable.a1,R.drawable.a2,R.drawable.a3,R.drawable.a4,R.drawable.a5};  
  24.     //文本资源  
  25.     private static final String[] intro={"神挡杀神,佛挡杀佛","仿佛兮若轻云之蔽月,飘飘兮若流风之回雪",  
  26.                                  "此乃驱狼吐虎之计,敬你之手他一搏吧","汝等小儿,可敢杀我",  
  27.                                  "汝等看好了"};  
  28.     private static int iCur=-1;  
  29.       
  30.     //周期更新时调用  
  31.     @Override  
  32.     public void onUpdate(Context context,AppWidgetManager appWidgetProvider,int[] appWidgetIds)  
  33.     {  
  34.         Log.v("创建Widget""OK");  
  35.         // 每次 widget 被创建时,对应的将widget的id添加到set中  
  36.         for(int id:appWidgetIds)  
  37.             hashSet.add(Integer.valueOf(id));  
  38.           
  39.     }  
  40.       
  41.     //当桌面组件删除时调用  
  42.     @Override  
  43.     public void onDeleted(Context context,int[] appWidgetIds)  
  44.     {  
  45.         for(int id:appWidgetIds)  
  46.             hashSet.remove(id);  
  47.           
  48.         super.onDeleted(context, appWidgetIds);  
  49.     }  
  50.       
  51.     //当桌面提供的第一个组件创建时调用  
  52.     @Override  
  53.     public void onEnabled(Context context)  
  54.     {  
  55.         //启动服务  
  56.         context.startService(AppWidget_Service);  
  57.           
  58.         super.onEnabled(context);  
  59.     }  
  60.       
  61.     //当桌面提供的最后一个组件删除时调用  
  62.     @Override  
  63.     public void onDisabled(Context context)  
  64.     {  
  65.         //停止服务  
  66.         context.stopService(AppWidget_Service);  
  67.           
  68.         super.onDisabled(context);  
  69.     }  
  70.       
  71.     /* 
  72.      * 重写广播接收方法 
  73.      * 用于接收除系统默认的更新广播外的  自定义广播(本程序由服务发送过来的,一个是更新UI,一个是按钮事件消息) 
  74.      */  
  75.     @Override  
  76.     public void onReceive(Context context,Intent intent)  
  77.     {  
  78.         String getAction=intent.getAction();  
  79.         if(getAction.equals(Constant.ACTION_UPDATE_ALL))  
  80.         {  
  81.             //更新广播  
  82.               
  83.             updateAllWidget(context,AppWidgetManager.getInstance(context), hashSet);  
  84.         }  
  85.         else if(intent.hasCategory(Intent.CATEGORY_ALTERNATIVE))  
  86.         {  
  87.             Uri data=intent.getData();  
  88.             Log.v("button",data.toString()+" ");  
  89.             int buttonid=Integer.parseInt(data.getSchemeSpecificPart());  
  90.             Toast.makeText(context, intro[buttonid],Toast.LENGTH_SHORT).show();  
  91.         }  
  92.           
  93.         super.onReceive(context, intent);  
  94.     }  
  95.       
  96.     //更新UI  
  97.     public void updateAllWidget(Context context,AppWidgetManager manager,HashSet<Integer> set)  
  98.     {  
  99.         int AppId;  
  100.         Iterator iterator=set.iterator();  
  101.           
  102.         iCur=iCur+1>=intro.length? 0: iCur+1;  
  103.           
  104.         while(iterator.hasNext())  
  105.         {  
  106.             AppId=((Integer)iterator.next()).intValue();  
  107.               
  108.             RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.activity_main);  
  109.             //设置显示的文字图片  
  110.             remoteViews.setTextViewText(R.id.textview_1, intro[iCur]);  
  111.             remoteViews.setImageViewResource(R.id.imageview_1, ResId[iCur]);  
  112.             //添加按钮事件处理  
  113.             remoteViews.setOnClickPendingIntent(R.id.button_1, getPendingIntent(context, iCur));  
  114.             //更新  
  115.             manager.updateAppWidget(AppId, remoteViews);  
  116.         }  
  117.     }  
  118.       
  119.     //设置按钮事件处理  
  120.     private PendingIntent getPendingIntent(Context context,int buttonid)  
  121.     {  
  122.         Intent intent=new Intent("test.test");  
  123.         intent.setClass(context, MyAppWidgetProvider.class);  
  124.         intent.addCategory(Intent.CATEGORY_ALTERNATIVE);  
  125.         intent.setData(Uri.parse("custom:"+buttonid));  
  126.         //进行广播  
  127.         PendingIntent pi=PendingIntent.getBroadcast(context, 0, intent, 0);  
  128.         return pi;  
  129.     }  
  130. }  

4、创建后台服务,用来定时发送广播,通知Widget需要更新了

MyAppWidgetService。class

[java]  view plain copy
  1. package com.feature.test;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.os.IBinder;  
  7.   
  8. public class MyAppWidgetService extends Service{  
  9.   
  10.     private Context context;  
  11.     //更新周期  
  12.     private static final int UPDATE_TIME=5000;  
  13.     //周期性更新的Widget 线程  
  14.     private WidgetThread widgetThread;  
  15.       
  16.     @Override  
  17.     public IBinder onBind(Intent intent) {  
  18.         // TODO Auto-generated method stub  
  19.         return null;  
  20.     }  
  21.   
  22.     @Override  
  23.     public void onCreate()  
  24.     {  
  25.         widgetThread=new WidgetThread();  
  26.         widgetThread.start();  
  27.           
  28.         context=this.getApplicationContext();  
  29.         super.onCreate();  
  30.     }  
  31.       
  32.     @Override  
  33.     public void onDestroy()  
  34.     {  
  35.         if(widgetThread!=null&&widgetThread.isAlive())  
  36.             widgetThread.interrupt();  
  37.           
  38.         super.onDestroy();  
  39.     }  
  40.       
  41.     private class WidgetThread extends Thread  
  42.     {  
  43.         @Override  
  44.         public void run()  
  45.         {  
  46.             try  
  47.             {  
  48.                 while(true)  
  49.                 {  
  50.                     Intent intent=new Intent(Constant.ACTION_UPDATE_ALL);  
  51.                     context.sendBroadcast(intent);  
  52.                       
  53.                     sleep(UPDATE_TIME);  
  54.                 }  
  55.             }catch(InterruptedException error)  
  56.             {  
  57.                 // 将 InterruptedException 定义在while循环之外,意味着抛出 InterruptedException 异常时,终止线程。  
  58.             }  
  59.         }  
  60.     }  
  61. }  

5、在AndroidManifest.xml注册Widget和服务

[java]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.feature.test"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >    
  6.    
  7.     <uses-sdk android:minSdkVersion="8"  android:targetSdkVersion="8"/>  
  8.     <application  
  9.         android:allowBackup="true"  
  10.         android:icon="@drawable/ic_launcher"  
  11.         android:label="@string/app_name"  
  12.         android:theme="@android:style/Theme.Black" >  
  13.         <!-- 注册AppWidget Provider -->  
  14.         <receiver   
  15.             android:name="com.feature.test.MyAppWidgetProvider">  
  16.             <meta-data android:name="android.appwidget.provider"  
  17.                        android:resource="@xml/mywidget_provider"  
  18.                        />  
  19.             <intent-filter >                                        
  20.                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />  
  21.                 <action android:name="com.feature.test.update_all" />  
  22.             </intent-filter>  
  23.         </receiver>  
  24.           
  25.         <!-- 注册服务 -->  
  26.         <service android:name=".MyAppWidgetService">  
  27.             <intent-filter>  
  28.                 <action android:name="com.feature.test.MyAppWidgetService"/>  
  29.             </intent-filter>  
  30.         </service>  
  31.               
  32.               
  33.     </application>  
  34.   
  35. </manifest>  

至此大功告成!有问题请、意见请回复,本人虚心求教委屈


另外:

1、如果你手机安装了自己做的Widget,在添加-窗口小工具显示不出来,那是因为你把它装到SD卡导致的,请在应用程序里找到自己的Widget将其移至手机存储即可显示

2、如果你安装的Widget放到桌面上,一直在显示“正在加载窗口小工具”,说明该Widget使用了您手机版本不支持的Widget控件,如EditText,使用它就会报错


转载地址:http://blog.csdn.net/tabactivity/article/details/9923281

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值