android学习笔记のAppWidget

来源:互联网 发布:武媚娘传奇未剪胸 知乎 编辑:程序博客网 时间:2024/05/18 00:24

appwidget的功能非常有限 

如果你的widget里面有一个TextView的话,你甚至无法得到这个控件中的文字内容,不要想用getText()方法,因为appwidget只支持一种对其包含控件的访问方法: 

RemoteViews  rv = new RemoteViews(packageName, layoutId); 

rv中包含一些设置属性的方法 

比如:setTextViewText(viewId, text)等 

但是不支持一切getxxx方法 

因此,你只能将数据呈现到appwidget上面。但是,你或许会遇到这种情况:从一个activityservice中获取数据显示到appwidget,当用户进一步操作时(点击了appwidget上的一个按钮),appwidget将会启动另一个activity或者service,并将数据传输给它。例如:启动一个dialog对话框activity让用户输入搜索关键字,用户点击确定之后,关键字会出现在appwidget上,再点击appwidget上的搜索按键,appwidget会启动浏览器,跳转到搜索页面。 

如果以上情况,开发者不可能从appwidget中获取到关键字,因此,比较好的解决方法是利用sharedPreference,将关键字存储进sharedPreference,无论是appwidgetUI显示,还是浏览器activity获取关键字的操作,全部变成读取sharedPreference数据。当然,也可以用其存储方式。

什么是appwidget? 即application widget。 应用程序控件,就是在桌面显示的控件。AppWidget就是我们平常在桌面上见到的那种一个个的小控件,利用这个小控件可以给用户提供一些方便快捷的操作。

创建一个简单的appwidget

相关概念:

1AppWidgetProviderInfo对象:它是一个xml文件,为appWidget提供元数据,包括布局,更新频率等数据。这个对象定义在xml中。

2AppWidgetProvider: 定义了appwidget的基本生命周期函数。

代码:

1、在layout中新建一个appwidgetlayout.xml文件。

 

Java代码  

<?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:id="@+id/textview"  

    android:layout_width="fill_parent"   

    android:layout_height="wrap_content"   

    android:text="@string/hello"  

    />  

</LinearLayout  

只是一个textview。这个是应用程序在桌面的控件。

2、在res中新建一个xml包,在这个包中新建一个appwidget_info.xml文件。 

Java代码  

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"  

    android:minWidth="294dp"  

    android:minHeight="72dp"  

    android:updatePeriodMillis="86400000"  

    android:initialLayout="@layout/appwidgetlayout"  

    />  

这个xmlappwidget提供元数据,这个是在桌面的布局,而这个layoutappwidgetlayout)为在appwidget中控件的布局。

3、在包下新建我们的provider,他继承了AppWidgetProvider,只需要对它的生命周期进行处理就行了。

 

Java代码  

public class AppWidgetprovider extends AppWidgetProvider {  

  

    @Override  

    public void onDeleted(Context context, int[] appWidgetIds) {  

        // TODO Auto-generated method stub  

        System.out.println("onDeleted");  

        super.onDeleted(context, appWidgetIds);  

    }  

  

    @Override  

    public void onDisabled(Context context) {  

        // TODO Auto-generated method stub  

        System.out.println("onDisable");  

        super.onDisabled(context);  

    }  

  

    @Override  

    public void onEnabled(Context context) {  

        // TODO Auto-generated method stub  

        System.out.println("onEnable");  

        super.onEnabled(context);  

    }  

  

    @Override  

    public void onReceive(Context context, Intent intent) {  

        // TODO Auto-generated method stub  

        System.out.println("onreceive");  

        super.onReceive(context, intent);  

    }  

  

    @Override  

    public void onUpdate(Context context, AppWidgetManager appWidgetManager,  

            int[] appWidgetIds) {  

        // TODO Auto-generated method stub  

        System.out.println("onUpdate");  

        super.onUpdate(context, appWidgetManager, appWidgetIds);  

    }  

      

}  

   

4、在AndroidManifest.xml中进行配置,由于这个appwidget使用的是广播机制,我们需要在AndroidManifest.xml中进行如下配置:

Java代码  

<receiver android:name="AppWidgetprovider">  

    <intent-filter >  

        <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>  

    </intent-filter>  

    <meta-data android:name="android.appwidget.provider"  

        android:resource="@xml/appwidget_info"  

    />  

</receiver>  

通过过滤器截取APPWIDGET_UPDATE这个action,然后对provider进行资源配置,对应的刚刚那个xml中的文件。

androidappwidget(二)启动新activity

appwidget的周期函数对应的事件:

onUpdate:到达指定时间之后或者用户向桌面添加appwidget时候会调用这个方法。

onDelete:当appwidget被删除时,会调用这个方法。

onEnable:当一个appwidget第一次被创建,会调用这个方法。

onDisable:当最后一个appwidget实例被删除后,会调用这个方法。

onReveice:接受广播事件。

appwidget交互:

功能:创建一个appwidget(为一个button),点击后,启动一个activity

1appwidget与对应的activity不是同一个进程,appwidgethomescreen中的一个进程。所以,不能直接对某一个控件进行事件监听,而是通过RemoteViews进行处理,而且我们也不能直接用intent进行启动activity,用pendingintent

2pendingintent:顾名思义,是还未确定的Intent。可以看做是对intent的一个包装,目的是对RemoteViews进行设置。形象点讲就是进程A中的intent想要在进程B中执行,需要pendingintent进行包装,然后添加到进程B中,进程B中遇到某个事件,然后执行intent

创建pendingintent有三个方法:getActivity(context,requestCode,intent,flags)getService()getBroadcast()

3RemoteViews:即远程的views它的作用是它所表示的对象运行在另外的进程中。

代码:

1appwidget.xml中(即桌面控件上加上一个Button)代码:

Java代码  

<span style="font-size: x-small;">    <Button   

        android:id="@+id/button"  

        android:layout_width="wrap_content"   

        android:layout_height="wrap_content"   

        android:text="测试按钮"  

    /></span>  

 2、在provider中的onUpdate方法中进行处理:

Java代码  

<span style="font-size: x-small;">for(int i= 0;i<appWidgetIds.length;i++){  

            System.out.println(appWidgetIds[i]);  

            //intent  

            Intent intent = new Intent(context,Appwidget2Activity.class);  

            //创建一个pendingIntent。  

            PendingIntent pendingIntent = PendingIntent.getActivity(  

                    context, 0, intent, 0);  

            //创建一个remoteViews。  

            RemoteViews remoteViews  = new RemoteViews(  

                    context.getPackageName(), R.layout.appwidget);  

            //绑定处理器,表示控件单击后,会启动pendingIntent。  

            remoteViews.setOnClickPendingIntent(R.id.button, pendingIntent);  

            appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews);  

        }</span>  

因为可能有多个appwidget,所以要遍历。创建一个intent,与要启动的activity关联起来,然后根据该intent创建一个pendingintent。然后根据appwidget.xml创建一个remoteViews,然后对该views中的一个控件进行pendingintent绑定。

androidappwidget(三)自定义action广播

根据一个action而启动一个广播,从而完成需要的操作。

首先appwidget根本是基于广播事件的,这个从需要在AndroidManifest.xml配置receiver可以看出,既然是这样,那么也可以自己定义我们自己的action以及在provider中的onReceive中进行处理。

其次,需要知道appwidgetprovider的运行机制就更容易理解了,当appwidget有事件时就会发送一个广播(一个intent对象)到appwidgetprovider它首先会启动onReceive方法来接收action,然后根据action的值来决定调用onUpdateonDeleteonDisableonEnable中的一个方法,它的这些方法都与一个action对应。

下面的实例实现的是自己定义一个action,然后在appwidgetprovider中的onReceiver中截取,然后输出一句话。

代码如下:

1、首先在AndroidManifest.xml加入

Java代码  

<receiver android:name = "AppwidgetProvider">  

    <intent-filter>  

        <action  

android:name="android.appwidget.action.APPWIDGET_UPDATE"/>  

    </intent-filter>  

    <intent-filter >  

             <action android:name="hanl.UPDATE_ACTION"/>  

    </intent-filter>  

    <meta-data android:name="android.appwidget.provider"  

                android:resource="@xml/appwidget_info">  

    </meta-data>  

</receiver>  

增加了一个过滤器:action"hanl.UPDATE_ACTION"

2、在onUpdate函数内增加一个intent,为它设置actionhanl.UPDATE_ACTION,然后用pendingintent包装intent,然后进行事件绑定。这个在appwidget()有具体讲解。

Java代码  

<span>                 @Override  

    public void onUpdate(Context context, AppWidgetManager appWidgetManager,  

            int[] appWidgetIds) {  

        // TODO Auto-generated method stub  

            //intent  

            Intent intent = new Intent();  

//设置action,UPDATE_ACTION在上面定义的为static final String UPDATE_ACTION=hanl.UPDATE_ACTION;</span><span>  

            intent.setAction(UPDATE_ACTION);  

            //创建一个pendingIntent  

            PendingIntent pendingIntent = PendingIntent.getBroadcast(  

                    context, 0, intent, 0);  

            //创建一个remoteViews  

            RemoteViews remoteViews  = new RemoteViews(  

                    context.getPackageName(), R.layout.appwidget);  

            //绑定处理器,表示控件单击后,会启动pendingIntent  

            remoteViews.setOnClickPendingIntent(R.id.button, pendingIntent);  

            //更新  

            appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);  

        super.onUpdate(context, appWidgetManager, appWidgetIds);  

    }</span>  

3、然后在onReceive中进行拦截。 

Java代码  

   @Override  

ublic void onReceive(Context context, Intent intent) {  

// TODO Auto-generated method stub  

String action = intent.getAction();  

if(action.equals(UPDATE_ACTION))  

    System.out.println("onReceive-----"+action);  

super.onReceive(context, intent);  

androidappwidget(四)终 appwidget控件更新

RemoteViews:指的是appwidget中的所有的控件。

componentName:指的是appwidget整个这个对象。

由于appwidget与主进程不是同一个进程,所以不能像在主进程中那样的操作,先get一个控件,然后set一个控件。

 

目标:在appwidget中放入一个textview , 一个imageView,和一个button,我们点击这个button他的textview imageview都发生改变。

代码:

1、首先在appwidget.xml中放入控件:

Java代码  

<TextView    

    android:id="@+id/textview"  

    android:layout_width="fill_parent"   

    android:layout_height="wrap_content"   

    android:text="测试"  

    />  

   <Button   

        android:id="@+id/button"  

        android:layout_width="fill_parent"   

        android:layout_height="wrap_content"   

        android:text="测试按钮"  

    />  

    <ImageView   

        android:id="@+id/imageview"  

        android:layout_width="wrap_content"  

        android:layout_height="wrap_content"  

        android:src="@drawable/android_icon_125"  

    />  

2、然后在onReceive中进行操作:

    要对控件更新,需要几个要点:1、获得控件 2、改变过程 3、将结果显示出来。

获得控件与改变需要remoteView,而将结果update出来需要AppWidgetManagerComponentName。代码如下: 

Java代码  

@Override  

    public void onReceive(Context context, Intent intent) {  

        // TODO Auto-generated method stub  

        String action = intent.getAction();  

        if(action.equals(UPDATE_ACTION)){  

                System.out.println("onReceive-----"+action);      

                //新建一个remoteViews,对控件进行操作。  

                RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget);  

                //控件更新:  

                remoteViews.setImageViewResource(R.id.imageview, R.drawable.dialog_icon);  

                remoteViews.setTextViewText(R.id.textview, "XXXx!");  

                //更新桌面。  

                //获得appwidgetmanager  

                AppWidgetManager appwidgetManager = AppWidgetManager.getInstance(context);  

                //获得componentName。  

                ComponentName componentname = new ComponentName(context, AppwidgetProvider.class);  

                //更新:  

                appwidgetManager.updateAppWidget(componentname, remoteViews);  

        }  

        else  

            super.onReceive(context, intent);  

}