通过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. JSP中使用EL表达式

    EL表达式 :EL 全名为Expression Language,就是为了替代<%= %>脚本表达式. EL主要作用: 获取数据: EL表达式主要用于替换JSP页面中的脚本表达式,以从各种 ...

  2. 1、Task类构造函数

    Task类的构造函数接收一个无参无返回值的委托: 1: Task task = new Task(TaskMethod); 2: task.Start();例子:  task = new Task(( ...

  3. C# json 总结

    json格式字符串转换为实体类,大括号 {} 表示对象,[] 数组表示列表. json文件读取到内存中就是字符串,.NET操作json就是生成与解析json字符串. 添加引用:using Newton ...

  4. Moodle 中文 API 之 文件管理API

    File API  文件管理 文件夹 1. 概述 2. 文件域 2.1 命名文件域 3. 提供文件给用户 4. 从用户那获取文件 5. 样例 5.1 浏览文件 5.2 移动文件 5.3 文件列表 5. ...

  5. Windows Server 2016 上配置 APACHE+SSL+PHP+perl

    Windows Server 2016 上配置 APACHE+SSL+PHP+perl 安装环境 谷歌云实例 Windows Server 2016 Apache Apache/2.4.25 (win ...

  6. PDF.Js的使用—javascript中前端显示pdf文件

    PDF.Js的使用—javascript中前端显示pdf文件 写于2018/12/6 起因是一个图片展示页面需要展示pdf格式的文件,所以查了半天决定使用pdf.js,我也不求有多了解它,能实现我想要 ...

  7. 4. Vue-Resource / axios 异步插件

    安装 cnmp i vue-resource --save (--save 安装到dependencies下) 引用 <script src="node_modules/vue-res ...

  8. [UWP]为什么ContentControl的ContentTemplate里放两个ContentPresenter会出问题(绕口)

    原文:[UWP]为什么ContentControl的ContentTemplate里放两个ContentPresenter会出问题(绕口) 1. 简单的HeaderedContentControl 上 ...

  9. 各大免费邮箱邮件群发账户SMTP服务器配置及SMTP发送量限制情况

    网络产品推广和新闻消息推送时,经常用到的工具就是用客户邮箱发送邮件了,如果是要发送的邮件量非常大的话,一般的建议是搭建自己的邮局服务器,或者是花钱购买专业的邮件群发服务,免费邮箱的SMTP适合少量的邮 ...

  10. 洛谷 P2646 数数zzy

    P2646 数数zzy 题目描述 zzy自从数学考试连续跪掉之后,上数学课就从来不认真听了(事实上他以前也不认真听).于是他开始在草稿纸上写写画画,比如写一串奇怪的字符串.然后他决定理♂性♂愉♂悦♂一 ...