通过widget定义,我们在widget列表中看到了我们的TestWidget。当我们拖拽widget到主页时,假设在appwidet-provider中定义了android:configure的java类,在widget实例创建后会立即唤起配置activity。

这个activity主要完毕两个任务:1、配置初始化数据;2、将配置数据适配到widget实例中。

利用preference中存贮配置数据

widget数据能够保持在文件、Share preference,或者SQLite3中。widget作为小工具配置数据量小,通常能够方便地存贮在preference中。preference中数据存贮和读取使用BirthDayStoreData类来处理。我们在Pro
Android学习笔记(六三):Preferences(7):代码控制首选项
中的“利用preference保存状态”已经介绍过怎样实现。在此,复习一下。

我们须要存贮的内容有widgetID,名字,生日,Preference是以键值对的方式保存。我们以name_widgetID作为key,生日作为value来进行信息存贮。

public class BirthDayStoreData { 

    private final static String BIRTHDAY_WIDGET_PROVIDER_NAME = "cn.wei.flowingflying.testwidget.provider"; 



    //保存配置数据:创建widget实例,通过configure activity进行配置时,保存相关配置数据 

    public static void storeData(Context context,int widgetId, String name,String value){

        String key = getKey(widgetId,name);            

        //第一个參数是preferences文件。假设不存在则创建之。详细为/data/data/cn.wei.flowingflying.testwidget/shared_prefs/cn.wei.flowingflying.testwidget.provider.xml,能够在DDMS中查看。

        Editor editor = context.getSharedPreferences(BIRTHDAY_WIDGET_PROVIDER_NAME, Context.MODE_PRIVATE).edit();

        editor.putString(key, value); 

        editor.commit();
    

    } 



    //删除配置数据:删除widget实例的同一时候,须要删除该实例的相关数据

    public static void removeData(Context context, int widgetId){ 

        String key = getKeyById(context, widgetId); 

        if(key == null) 

            return; 

        Editor editor = context.getSharedPreferences(BIRTHDAY_WIDGET_PROVIDER_NAME, Context.MODE_PRIVATE).edit();

        editor.remove(key); 

        editor.commit(); 

    } 

    //清空所有的配置数据 

    public static void removeAllData(Context context){ 

        Editor editor = context.getSharedPreferences(BIRTHDAY_WIDGET_PROVIDER_NAME, Context.MODE_PRIVATE).edit();

        editor.clear(); 

        editor.commit();        

    }    



    //显示配置数据:用于我们在LogCat中进行跟踪,在此,我们也演示了怎样通过轮询方式,显示所有的数据。通过类似的方式,我们能够同widgetId查得相应的名字和生日。通过类似的方法,可依据widgetId查询key,名字,生日,相关代码从略。

    public static void showData(Context context){ 

        SharedPreferences prefs = context.getSharedPreferences(BIRTHDAY_WIDGET_PROVIDER_NAME, Context.MODE_PRIVATE);

        Map<String,?

> pairs = prefs.getAll();  

        Log.d("DATA","Total " + pairs.size() + " widgets:");

        for(String key:pairs.keySet()){ 

           String value = (String)pairs.get(key);
 

            Log.d("DATA",key + " - " + value);

       } 

    }  

     

    public static String getNameById(Context context, int widgetId){ 

        … … 

    } 

    

    public static String getDateById(Context context ,int widgetId){ 

        … …   

    } 

    

    private static String getKey(int widgetId, String name){ 

        return name + "_" + widgetId; 

    }   

     

    private static String getKeyById(Context context,int widgetId){  

        … … 

    }  

    

}

配置初始化数据

配置configure activity的代码例如以下:

public class ConfigBirthDayWidgetActivity extends Activity{ 

    private static String tag = "ConfigActivity"; 

    private int myWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; 

    

    @Override //配置activity的操作和普通activity的一样,但在被AppWidgetManage唤起时,intent是携带widgetId的信息。我们在onCreate()中获取Widget ID。 

    protected void onCreate(Bundle savedInstanceState) { 

        … …  

        Intent intent = getIntent(); 

        Bundle b = intent.getExtras(); 

        if(b != null){ 

            myWidgetId = b.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);           

        } 

        

        if(myWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID){  

            Toast.makeText(this, "Widget Error : 无有效widget ID", Toast.LENGTH_LONG).show();

            finish(); 

        }  



    } 

    

    .. ….  

      

   //点击配置button后调用的方法 

    private void getAndStoreConfigInfo(){  

        … …  String name为用户输入名字,String date为用户输入的有效日期

        //【1】在preference中保持数据,并显示全部数据 

        BirthDayStoreData.storeData(this, myWidgetId, name, date);

        BirthDayStoreData.showData(this); 

        //【2】将配置数据与详细的widget实例相关联,详细实现见后面

        BirthDayStoreData.updateAppWidget(this, myWidgetId,name, date); 

        

        //【3】将结果返回给AppWidget Manager,以通知它Configurator已经完毕。

作用如同startActivityForResult()给出返回值,通知AppWidgetManager某个widgetId已经完毕配置,能够在主页上显示创建的widget实例 

        Intent resultIntent = new Intent(); 

        resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, myWidgetId);

        setResult(RESULT_OK, resultIntent);
 

        //【4】关闭activity

        finish(); 

    }      

}

配置数据适配到widget实例中

Widget实例的view要通过RemoteViews进行控制,小样例採用静态方法的方式。代码片段例如以下:

public class BirthDayStoreData {  

    ... ... 

      

    public static void updateAppWidget(Context context,int widgetId,String name, String date){

       //【1】设置Remote view的信息 

        // 1.1)、获得remote view对象

        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.birday_widget);

        // 1.2)、对remote view进行setText()设置

        views.setTextViewText(R.id.bd_name, widgetId + ":" + name);

        views.setTextViewText(R.id.bd_date, date);  

        views.setTextViewText
(R.id.bd_days, Long.toString(Utils.howFarInDays(Utils.getDate(date))));//Utils是处理日期的类

        // 1.3)、通过PendingIntent设置某个view的点击处理,採用intent方式,能够打开activity。service,receiver等等。

本小样例将打开某个网页 

        Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.taobao.com"));

        PendingIntent pi = PendingIntent.getActivity(context, 0, intent, 0); 

        views.setOnClickPendingIntent(R.id.bd_buy, pi);
 

        

        //【2】通过AppWidgetManger。详细实施到widgetId实例上。



        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

        appWidgetManager.updateAppWidget(widgetId,views);
 

    } 

    

    public static void updateAppWidget(Context context,int widgetId){

        … …  

    }

}

依据widget定义,我们App Widget Provider的Java类为BirthDayWidgetProvider。这个类用于管理Widget的各个生命周期。

public class BirthDayWidgetProvider extends AppWidgetProvider{ 

    private static String tag = "BirthDayWidgetProvider"; 



    @Override /* 在3种情况下会调用OnUpdate()。onUpdate()是在main线程中进行,因此假设处理须要花费时间多于10秒,处理应在service中完毕。

(1)在时间间隔到时调用,时间间隔在widget定义的android:updatePeriodMillis中设置; 

(2)用户拖拽到主页。widget实例生成。
不管有没有设置Configure activity,我们在Android4.4的測试中,当用户拖拽图片至主页时。widget实例生成,会触发onUpdate()。然后再显示activity(假设有)。这点和资料说的不一样,资料觉得假设设置了Configure acitivity,就不会在一開始调用onUpdate(),而实验显示当实例生成(包含创建和重新启动时恢复)。都会先调用onUpate()。

在本例,因为此时在preference尚未有相关数据。创建实例时不能有效进行数据设置。

(3)机器重新启动。实例在主页上显示,会再次调用onUpdate()*/ 

   public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 

        Log.d(tag,"onUpdate() called. 有 " + appWidgetIds.length + "个widgets");   

        for(int i = 0 ; i< appWidgetIds.length; i ++){ 

            Log.d(tag,"update widget ID " + appWidgetIds[i]);

            BirthDayStoreData.updateAppWidget(context, appWidgetIds[i]); 

        } 

    } 



    @Override  /* 某个/些widget从主页中删除,在此删除该widget的相关数据  */

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

        Log.d(tag,"onDeleted() called"); 

        for(int i = 0 ; i < appWidgetIds.length; i ++){ 

            Log.d(tag,"delete widget " + appWidgetIds[i] + " data");

            BirthDayStoreData.removeData(context, appWidgetIds[i]); 

        } 

        BirthDayStoreData.showData(context); 

    } 

    

    @Override /* 一般无需重写此方法。App Widget provider本质是receiver,在此能够跟踪收到什么消息。这些消息包含AppWidgetManager.ACTION_APPWIDGET_DELETED/UPDATE/ENABLED/DISABLED,super.onReceiver()会依据消息类型触发不同的回调函数。假设採用AlarmManager或者自己定义的广播,能够再次进行处理。
*/ 

    public void onReceive(Context context, Intent intent) {
  

        Log.i(tag,"onReceive() : " + intent);  

        super.onReceive(context, intent);  

    }      



    @Override  /* 表明至少有一个widget实例被拖到主页上,即当第一个widget出现时的回调函数。

我们须要同意广播接收器接收消息,第一个widget出现了。

我们能够在此注冊其他感兴趣的自己定义的广播*/

    public void onEnabled(Context context) {
  

        Log.d(tag,"onEnabled() called, context " + context.toString());          

        // setComponentEnabledSetting相当于在AndriodMenifest.xml文件里队组件设置android:enabled为true|false。此处是对receiver进行设置,假设true。则同意进行监听,包含开机重新启动。 

        PackageManager pm = context.getPackageManager(); 

      /*使用new ComponentName("cn.wei.flowingflying.testwidget",".BirthDayWidgetProvider")出现不明原因错误,

        * 可对类名採用全然名称。及new ComponentName("cn.wei.flowingflying.testwidget", 

        *                               "cn.wei.flowingflying.testwidget.BirthDayWidgetProvider"),

        * 或通过系统获取组件名的方式new ComponentName(context, getClass())*/ 

        pm.setComponentEnabledSetting(new ComponentName(context, getClass()),

                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 

                PackageManager.DONT_KILL_APP);         

    } 



    @Override  /*最后一个widget已从主页中删除,在此,确保删除全部配置数据。无需进行广播监听,色织enabled=false。假设有注冊的自己定义广播,在此unregister */

    public void onDisabled(Context context) {  

        BirthDayStoreData.removeAllData(context); 

        PackageManager pm = context.getPackageManager(); 

        pm.setComponentEnabledSetting(new ComponentName(context, getClass()), 

                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 

                PackageManager.DONT_KILL_APP);          

    } 



}

假设主页没有实例,新实例的生成触发顺序为:onEnabled() –>onUpdate() –>Configure Activity,头两个顺序可能会出现变化。预计是AppWidgetManager的异步处理导致广播消息出现的先后顺序问题。假设已经有实例,新实例生成触发顺序为onUpdate() –> Configure activity。配置后,等待定义的时间间隔,进行定期触发onUpdate()。

机器重新启动 onEnabled() –>onUpdate() –> onUpdate(),相同头两个顺序可能会交换,此后。等待widget定义的时间间隔,进行定期触发onUpdate()。

假设我们更新或重装apk,实例并不会被删除,会触发onUpdate()。

补充:Widget图标

Widget在widget列表中显示的通常都是widget的外貌,Android模拟器有一个应用Widget Preview能够帮助我们获取widget的外观图标。例如以下:

通过adb pull将存贮在模拟器SD卡Download路径下的preview图片获取。作为列表显示图标。

Android学习笔记:Home Screen Widgets(2):关于Widget的更多相关文章

  1. Pro Android学习笔记(一三七):Home Screen Widgets(3):配置Activity

    文章转载仅仅能用于非商业性质,且不能带有虚拟货币.积分.注冊等附加条件.转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei. 通过widget定义 ...

  2. 【转】 Pro Android学习笔记(五七):Preferences(1):ListPreference

    目录(?)[-] 例子1ListPreference小例子 定义一个preferences XML文件 继承PreferenceActivity 用户定制偏好的读取 第一次运行时设置缺省值 设置Cat ...

  3. 【转】Pro Android学习笔记(四):了解Android资源(下)

    处理任意的XML文件 自定义的xml文件放置在res/xml/下,可以通过R.xml.file_name来获取一个XMLResourceParser对象.下面是xml文件的例子: <rootna ...

  4. 【转】Pro Android学习笔记(三):了解Android资源(上)

    在Android开发中,资源包括文件或者值,它们和执行应用捆绑,无需在源代码中写死,因此我们可以改变或替换他们,而无需对应用重新编译. 了解资源构成 参考阅读Android学习笔记(三八):资源res ...

  5. Android 学习笔记之Volley(七)实现Json数据加载和解析...

    学习内容: 1.使用Volley实现异步加载Json数据...   Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...

  6. Android学习笔记进阶之在图片上涂鸦(能清屏)

    Android学习笔记进阶之在图片上涂鸦(能清屏) 2013-11-19 10:52 117人阅读 评论(0) 收藏 举报 HandWritingActivity.java package xiaos ...

  7. android学习笔记36——使用原始XML文件

    XML文件 android中使用XML文件,需要开发者手动创建res/xml文件夹. 实例如下: book.xml==> <?xml version="1.0" enc ...

  8. Android学习笔记之JSON数据解析

    转载:Android学习笔记44:JSON数据解析 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种 ...

  9. udacity android 学习笔记: lesson 4 part b

    udacity android 学习笔记: lesson 4 part b 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 ...

随机推荐

  1. absolute、relative,toggle()

    測试代码例如以下: <div> <div class="global">不应用样式</div> <div class="glob ...

  2. 20亿与20亿表关联优化方法(超级大表与超级大表join优化方法)

    记得5年前遇到一个SQL.就是一个简单的两表关联.SQL跑了几乎相同一天一夜,这两个表都非常巨大.每一个表都有几十个G.数据量每一个表有20多亿,表的字段也特别多. 相信大家也知道SQL慢在哪里了,单 ...

  3. Intent调用系统拍照程序,返回图片太小的问题

    之前採用的方式(返回的照片会被压缩,不能达到预期效果): Intent intent = new Intent(); Intent intent_camera = getPackageManager( ...

  4. Angular:了解Typescript

    Angular是用Typescript构建的.因此在学习Angular之前有必要了解一下Typescript. [ 类型 ] Typescript增加了类型系统,好处是: 1. 有助于代码编写,预防在 ...

  5. Vue router的query对象里的值的问题

    在使用 $router.push() 时,如果使用了query,则可以在跳转后从query中获取到对应的参数.如果传的是字符串自然没问题,但是如果传的其他类型的数据,在跳转之后是正常的,而跳转之后再刷 ...

  6. 【Codeforces Round #451 (Div. 2) C】Phone Numbers

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 用map<string,vector > dic;模拟就好. 后缀.翻转一下就变成前缀了. 两重循环剔除这种情况不输出就 ...

  7. PHP用socket连接SMTP服务器发送邮件

    PHP用socket连接SMTP服务器发送邮件 PHP用socket连接SMTP服务器发送邮件学习实验记录: 分析与SMTP会话的一般流程 1. HELO XXX \r\n //XXX就是自己起个名字 ...

  8. Android学习笔记之按键操作

    我们如何和Android 程序来进行交互那份?来让 Android 程序产生相应的反应,我们不得不通过键盘事件.触摸事件.传感器事件等来实现. 键盘是Android中主要的输入设备,对按键的响应的处理 ...

  9. Android学习笔记之网络接口(Http接口,Apache接口,Android接口)

    目前Android平台有三种网络接口可以使用,他们分别是:Java.NET.*(标准Java接口),org.apache(Apache接口),和android.Net.*(android网络接口). ...

  10. Linux常用运维命令小结

    1. 空设备文件以及标准输入输出 /dev/null 表示空设备文件 0 表示stdin标准输入 1 表示stdout标准输出 2 表示stderr标准错误 2>&1 这里有两种解释:将 ...