zoukankan      html  css  js  c++  java
  • android 桌面小工具(Widget)开发教程

    刚学做了个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指示了更新间隔,8640000024小时,也就是一天一次,本程序自己采用后台服务更新,所以该设置其实对本程序来说关系不大。 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,使用它就会报错

  • 相关阅读:
    JS中检测数据类型的方式
    DOM库
    原型应用(将数组去重写到数组的原型上)
    JS学习之原型和原型链模式
    JS学习之闭包、this关键字、预解释、作用域综合
    JS学习之作用域
    JS学习之预解释
    maven gradle 混合使用的问题
    libgdx 开发环境搭建
    maven 安装 jar
  • 原文地址:https://www.cnblogs.com/xieyuan/p/3787384.html
Copyright © 2011-2022 走看看