博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 知识总览
阅读量:5150 次
发布时间:2019-06-13

本文共 26851 字,大约阅读时间需要 89 分钟。

activity 显示界面(显示的界面都是继承activity完成的) service 服务(后台运行的,可以理解为没有界面的activity) Broadcast Receiver 广播(做广播,通知时候用到) Content Provider  数据通信(数据之间通信,同个程序间数据,或者是不同程序间通信) ---------------------------------------------------------------------------------------------------------------

1.Intent的作用

一个Intent对象包含了一组信息:

Component name组件名称:intent会根据component name要启动哪一个组件(activity,service,contentProvider)

Action://ACTION_CALL、ACTION_EDIT。。。指定另外一个Activity要做些什么

Data:从一个Activity向另一个Activity传送怎样的数据

Category

Extras额外的:事先向一个activity的intent中存入的键值对

Flags

注意:Activity之间通过intent传递数据不一定要求是在同一个应用中

 

2.Activity02.javapackage mars.activity02;import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button; public class Activity02 extends Activity {//代表按钮对象的引用private Button myButton = null;//复写父类当中的onCreate方法,Activity第一次运行时会调用这个方法    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //为Activity设置布局管理文件         setContentView(R.layout.main);        //以下两行代码是根据控件的ID来得到控件对象        myButton = (Button)findViewById(R.id.myButton);       //为按钮对象设置监听器对象        myButton.setOnClickListener(new MyButtonListener());    }    //以下是一个内部类,这个内部类的对象是一个监听器(如果大家对监听器不是很熟悉,可以参考设计模式当中的观察者模式)    class MyButtonListener implements OnClickListener{   //生成该类的对象,并将其注册到控件上。如果该控件被用户按下,就会执行onClick方法        public void onClick(View v) {       //生成一个Intent对象       Intent intent = new Intent();      //在Intent对象当中添加一个键值对,实现两个Activity之间数据的传送。      intent.putExtra("testIntent", "123");      //设置Intent对象要启动的Activity     intent.setClass(Activity02.this, OtherActivity.class);      //通过Intent对象启动另外一个Activity,这两个Activity不一定要同一个应用程序     Activity02.this.startActivity(intent);       }   }} 3.OtherActivity.javapackage mars.activity02;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.widget.TextView; public class OtherActivity extends Activity{private TextView myTextView = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.other);  //取得从上一个Activity当中传递过来的Intent对象   Intent intent = getIntent();  //从Intent当中根据key取得value,实现两个Activity之间数据的传送。   String value = intent.getStringExtra("testIntent");  //根据控件的ID得到响应的控件对象   myTextView = (TextView)findViewById(R.id.myTextView);  //为控件设置Text值   myTextView.setText(value);  }}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

Android之Widget

其实Android API开发指南中的App Widgets章节 已经说得很清楚了,下面只是对自己的理解进行一次梳理。 
-- 
AppWidget 就是HomeScreen上显示的小部件,提供直观的交互操作。通过在HomeScreen中长按,在弹出的对话框中选择Widget部件来进行创建,长按部件后并拖动到垃圾箱里进行删除。同一个Widget部件可以同时创建多个。 
AppWidget的实现主要涉及到以下类: AppWidgetProvider RemoteViews 
AppWidgetManager 
1. 
首先需要提供一个定义了Widget界面布局的XML文件(位于res/layout/..),需要注意的是使用的组件必须是RemoteViews所支持的,目前原生API中支持的组件如下: 
FrameLayout LinearLayout RelativeLayout 
AnalogClock 
Button Chronmeter ImageButton ImageView ProgressBar 
TextView 
*如果使用了除此之外的组件,则在Widget创建时会导致android.view.InflateExceptionn异常。 
PS:这就导致有一些功能或样式无法实现,如很基本的list或文本编辑框都是无法直接实现的。如果想自定义Widget中的View的话只能通过修改framework来提供相应组件的支持。 
2. 然后需要提供一个xml文件来定义Widget的基本属性,放置到res/xml/..目录下。 
如果使用的是Eclipse可按如下操作: 1) 在res/目录下创建xml/目录 
2)创建xml文件(名字可任意),选择类型为AppWidgetProvider 3)在弹出的便捷界面进行参数设置 
主要设置的参数如下: minWidth: 定义Wdiget组件的宽度 minHeight: 定义Wdiget组件的高度 
updatePeriodMillis: 更新的时间周期 initialLayout: Widget的布局文件 
configure: 如果需要在启动前先启动一个Activity进行设置,在这里给出Activity的完整类名(后面会说到,与一般Activity的实现有些许差别) 
*Widget大小的计算单元格数*74)-2,API上说是为了防止像素计算时的整数舍入导致错所以-2...不是很明白 
一个完整的样例: Xml代码  收藏代码 
   
3. 
xml都定义好后,接下来就是创建一个继承自AppWidgetProvider的子类,AppWidgetProvider实际上就是一个BroadcastReceiver,里面提供了以下函数: 
onReceive(Context, Intent) 
onUpdate(Context , AppWidgetManager, int[] appWidgetIds) 
onEnabled(Context) onDeleted(Context, int[] appWidgetIds) 
onDisabled(Context) 可通过重写以上函数来监听Widget状态的变化并进行相应的处理。 
以上函数具体调用情况归纳如下: [启动 - 无confiure Activity] onReceive 
onEnabled —— 第一个widget被显示 onReceive onUpdate —— 刷新界面 
[启动 - 带confiuration Activity] onReceive onUpdate 
[拖动] 
<无状态变化> 
[周期更新] onReceive onUpdate 
[删除] 
onReceive onDeleted —— widget被删除 onReceive 
onDisabled —— 最后一个widget被移除 
[启动时位置不够] onReceive onEnabled 
onReceive onUpdate onReceive onDeleted onReceive 
onDisabled 
*每次状态的变化会触发onReceive,一般该函数是不需要重写的。 
简单了解AppWidgetProvider之后,我们来看具体实现。 
这里创建一个MyAppWidgetProvider继承AppWidgetProvider: Java代码  收藏代码 
  
其中onUpdate顾名思义是对Widget进行更新的,前面定义的更新周期就是作用于该函数的。 
Widget的更新与Activity不同,必须借助于RemoteViews和AppWidgetMananger。具体实现如下: 
Java代码  收藏代码 
    public void onUpdate(Context context, AppWidgetMananger appWidgetManager, int[] appWidgetIds){   
        int N = appWidgetIds.length; // 可能启动了多个Widget,appWidgetIds记录了这些Widget的ID   
        for(int i=0; i<N; i++){   
            RemoteViews  views = new RemoteViews(getPackageName(), R.layout.widget_views);   
            appWidgetManager.updateAppWidget(appWidgetIds[i], views);   
        }       }   
public class MyWidgetProvider extends AppWidgetProvider {                    static final String TAG = "widget";                         /**                    * 更新                  */             public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){                   Log.i(TAG, "onUpdate");             }                         /**             * 第一个Widget组件启动时触发             */             public void onEnabled(Context context){                   Log.i(TAG, "onEnabled");             }                         /**             * 最后一个Widget组件关闭时触发             */             public void onDisabled(Context context){                   Log.i(TAG, "onDisabled");             }                         /**             * 任一Widget组件被删除时触发             */             public void onDeleted(Context context, int[] appWidgetIds){                   Log.i(TAG, "onDeleted");             }                         /**             * 以上函数触发前会先触发该函数,一般不需要重写             */             public void onReceive(Context context, Intent intent){                   Log.i(TAG, "onReceive");                   super.onReceive(context, intent);             }                   }

 

其中需要注意的是,虽然RemoteViews参数都是一样的,但是对于每个Widget最好都新创建一个再进行传递,否则会导致一些错误。具体可参考AppWidget RemoteViews 内存溢出 。 
其他函数的可以根据需要实现。 
由于无法获取到RemoteViews创建的界面中的元素,对于Widget中组件的操作只能通过RemoteViews所提供的有限的函数进行,常用的有: 
setOnClickPendingIntent(int viewId, PendingIntent pendingIntent) 
setProgressBar(int viewId, int max, int progress, boolean indeterminate) 
setTextViewText(int viewId, CharSequence text) 
setViewVisibility(int viewId, int visibility) 
详细函数列表可参考API中的RemoteViews类 。 
4. 最后,更新AndroidManifest.xml。 
AppWidgetProvider对应一个receiver属性: Xml代码  收藏代码 
   
      
        

 

5. 
提供Configuration Activity 
Configuration Activity是一个在Widget启动前先启动的Activity,方便用户对Widget的属性进行设置。 
在res/xml/...下对应的"属性文件"中添加configure字段指定启动的Activity,并在 AndroidManifest.xml中该Activity下提供一个action为 android.appwidget.action.APPWIDGET_CONFIGURE 的IntenFilter。 
需要注意的是, 
如果设置了Configure属性,则必须在指定的Activity中进行如下处理: 
1.在onCreate中setContentView()函数前添加setResult(RESULT_CANCLE) ,这样如果在Activity初始化完成前按下了BACK按键,则Widget不会启动; 
2.在setContentView()函数之后(不一定要在onCreate中,在Activity退出前即可),添加如下设置以指定需要启动的Widget: 
Java代码  收藏代码 
   
int mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);       Intent resultValue = new Intent();       resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);       setResult(RESULT_OK, resultValue);

 

否则会导致退出Activity后Widget不启动。 
>> Widget创建步骤汇总: 1.定义Widget布局XML -> res/layout/... 
2.定义Widget属性文件(xml) -> res/xml/... 3.  创建AppWidgetProider子类,实现onUpdate()等函数,在manifest中注册receiver,添加一个action为  android.appwidget.action.APPWIDGET_UPDATE 的IntentFilter,并添加如下<meta-  data>标识: Xml代码  收藏代码 
    <meta-data android:resource="@xml/<属性文件xml>" android:name="android.appwidget.provider"></meta-data>   
4. 创建Coniguration  Activity(注意处理好setResult),添加到属性文件中的Configure属性,在manifest中注册activity,添加一个  action为android.appwidget.action.APPWIDGET_CONFIGURE 的IntentFilter 
最后附上一个完整的例子, 实现思路如下: 1. 提供一个Configuration Activity,这里只简单显示一行文字; 
2.退出后Widget启动;

----------------------------

Android 之窗口小部件高级篇--App Widget 之 RemoteViews - 跨到对岸去

Android 之窗口小部件高级篇--App Widget 之 RemoteViews

  在之前的一篇博文( t)中,已经介绍了App Widget的基本用法和简单实例。这篇主要讲解 App Widget 的高级内容,即通过 RemoteViews 去管理Widget的中GridView、ListView、StackView等内容。在学习本篇之前,建议读者先掌握 App Widget 的基本知识。

 

1 RemoteViews等相关类的介绍

下面先简单介绍RemoteViews、RemoteViewsService、RemoteViewsFactory。

1.1 RemoteViews

    顾名思义,它是一个远程视图。App Widget中的视图,都是通过RemoteViews表现的。 

    在RemoteViews的构造函数中,通过传入layout文件的id来获取 “layout文件对应的视图(RemoteViews)”;然后,调用RemoteViews中的方法能对layout中的组件进行设置(例如,可以调用setTextViewText()来设置TextView组件的文本,可以调用setOnClickPendingIntent() 来设置Button的点击响应事件)。

    因此,我们可以将 “RemoteViews 看作是 layout文件中所包含的全部视图的集合”。

1.2 RemoteViewsService

    RemoteViewsService,是管理RemoteViews的服务。 

    一般,当App Widget 中包含“GridView、ListView、StackView等”集合视图时,才需要使用RemoteViewsService来进行更新、管理。(集合视图是指GridView、ListView、StackView等包含子元素的视图) 
    RemoteViewsService更新“集合视图”的一般步骤是: 
(01) 通过setRemoteAdapter来设置 “RemoteViews对应RemoteViewsService”。 
(02) 之后在RemoteViewsService中,实现RemoteViewsFactory接口。然后,在RemoteViewsFactory接口中对“集合视图”的各个子项进行设置(“集合视图”的各个子项:例如,GridView的每一个格子都是一个子项;ListView中的每一列也是一个子项)。

    因此,我们可以将 “RemoteViewsService 看作是 管理layout中集合视图的服务”。

1.3 RemoteViewsFactory

    通过RemoteViewsService中的介绍,我们可以了解“RemoteViewsService是通过RemoteViewsFactory来具体管理layout中集合视图的”,即“RemoteViewsFactory管理集合视图的实施者”。 

    RemoteViewsFactory是RemoteViewsService中的一个接口。RemoteViewsFactory提供了一系列的方法管理“集合视图”中的每一项。例如: 
(01)RemoteViews getViewAt(int position) 
      通过getViewAt()来获取“集合视图”中的第position项的视图,视图是以RemoteViews的对象返回的。 
(02)int getCount() 
      通过getCount()来获取“集合视图”中所有子项的总数。

    因此,我们可以将 “RemoteViewsFactory 看作是 layout中集合视图管理的具体实施者”。

2 实例介绍

    实现一个App Widget,App Widget可缩放,且包含“3个组成部分”。 

第1部分:是一个TextView文本,标题内容是“Sky Wang”。 
第2部分:是一个Button按钮。点击按钮,会弹出一个Toast提示框,提示响应了Button点击事件。 
第3部分:是一个GridView视图。GridView的每一个格子包含“图片”和“文本”两部分数据。点击GridView中的每一个格子,会弹出响应的提示语。

manifest代码如下 :

说明: 

(01) GridWidgetProvider.java 是 AppWidgetProvider的继承类 ,而且AppWidgetProvider的配置文件是 widget_provider.xml 。 
(02) GridWidgetProvider.java 除了 响应 App Widget 的更新事件 (android.appwidget.action.APPWIDGET_UPDATE)之外; 
       也会“ 响应App Widget包含的GridView的点击事件 (com.skywang.test.COLLECTION_VIEW_ACTION) ”  和“ App Widget包含的按钮的点击事件 (com.skywang.test.BT_REFRESH_ACTION) ”。 
(03) GridWidgetService.java 是 RemoteViewsService的继承类 。

widget_provider.xml代码如下 : 

widget_provider.xml是AppWidgetProvider对应配置文件

说明: 

(01) android:minWidth="180dp"                                     表明 " Widget支持的最小宽度是3格 " 
(02) android:minHeight="180dp"                                   表明 " Widget支持的最小高度是3格 " 
(03) android:initialLayout="@layout/widget_layout" 表明 " Widget对应的布局文件是widget_layout.xml " 
(04) android:previewImage="@drawable/preview"     表明 " Widget对应的预览图片是preview.png " 
(05) android:resizeMode="horizontal|vertical"           表明 " Widget支持水平和竖直伸缩 " 
(06) android:widgetCategory="home_screen"            表明 " Widget只能添加到桌面上,而不能添加到锁屏界面上 "

 

widget_layout.xml代码如下 : 

widget_layout.xml是App Widget的布局文件

GridWidgetProvider.java代码如下 : 

GridWidgetProvider.java是AppWidgetProvider的继承类

package com.skywang.test;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.appwidget.AppWidgetProvider;import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.RemoteViews; import android.widget.Toast; import com.skywang.test.R; /** * @desc App Widget高级功能测试程序 * @author skywang * */ public class GridWidgetProvider extends AppWidgetProvider { private static final String TAG = "SKYWANG"; public static final String BT_REFRESH_ACTION = "com.skywang.test.BT_REFRESH_ACTION"; public static final String COLLECTION_VIEW_ACTION = "com.skywang.test.COLLECTION_VIEW_ACTION"; public static final String COLLECTION_VIEW_EXTRA = "com.skywang.test.COLLECTION_VIEW_EXTRA"; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Log.d(TAG, "GridWidgetProvider onUpdate"); for (int appWidgetId:appWidgetIds) { // 获取AppWidget对应的视图 RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); // 设置响应 “按钮(bt_refresh)” 的intent Intent btIntent = new Intent().setAction(BT_REFRESH_ACTION); PendingIntent btPendingIntent = PendingIntent.getBroadcast(context, 0, btIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setOnClickPendingIntent(R.id.bt_refresh, btPendingIntent); // 设置 “GridView(gridview)” 的adapter。 // (01) intent: 对应启动 GridWidgetService(RemoteViewsService) 的intent // (02) setRemoteAdapter: 设置 gridview的适配器 // 通过setRemoteAdapter将gridview和GridWidgetService关联起来, // 以达到通过 GridWidgetService 更新 gridview 的目的 Intent serviceIntent = new Intent(context, GridWidgetService.class); rv.setRemoteAdapter(R.id.gridview, serviceIntent); // 设置响应 “GridView(gridview)” 的intent模板 // 说明:“集合控件(如GridView、ListView、StackView等)”中包含很多子元素,如GridView包含很多格子。 // 它们不能像普通的按钮一样通过 setOnClickPendingIntent 设置点击事件,必须先通过两步。 // (01) 通过 setPendingIntentTemplate 设置 “intent模板”,这是比不可少的! // (02) 然后在处理该“集合控件”的RemoteViewsFactory类的getViewAt()接口中 通过 setOnClickFillInIntent 设置“集合控件的某一项的数据” Intent gridIntent = new Intent(); gridIntent.setAction(COLLECTION_VIEW_ACTION); gridIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, gridIntent, PendingIntent.FLAG_UPDATE_CURRENT); // 设置intent模板 rv.setPendingIntentTemplate(R.id.gridview, pendingIntent); // 调用集合管理器对集合进行更新 appWidgetManager.updateAppWidget(appWidgetId, rv); } super.onUpdate(context, appWidgetManager, appWidgetIds); } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); Log.d(TAG, "GridWidgetProvider onReceive : "+intent.getAction()); if (action.equals(COLLECTION_VIEW_ACTION)) { // 接受“gridview”的点击事件的广播 int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); int viewIndex = intent.getIntExtra(COLLECTION_VIEW_EXTRA, 0); Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show(); } else if (action.equals(BT_REFRESH_ACTION)) { // 接受“bt_refresh”的点击事件的广播 Toast.makeText(context, "Click Button", Toast.LENGTH_SHORT).show(); } super.onReceive(context, intent); } }

说明: 

(01) RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 
     通过上面的语句, 获取widget_layout.xml对应的 RemoteViews ;进而通过RemoteViews对 widget_layout.xml中的各个元素进行管理。 
(02) rv.setOnClickPendingIntent(R.id.bt_refresh, btPendingIntent); 
     通过上面的语句,设置 点击“按钮(bt_refresh)”时会触发的Intent 。从而对按钮点击事件进行处理。 
(03) rv.setRemoteAdapter(R.id.gridview, serviceIntent); 
    通过上面的语句, 设置 “GridView(gridview)” 的远程适配器 ,serviceIntent是 GridWidgetService 的Intent。 
    从而在通过GridWidgetService对gridview进行管理。 
(04) PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, gridIntent, PendingIntent.FLAG_UPDATE_CURRENT); 
    通过上面的语句,设置响应 “GridView(gridview)” 点击事件的 intent模板 。关于“Intent模板”,后面在" 关于'GridView'的点击事件 "会详细说明。 
(05) if (action.equals(COLLECTION_VIEW_ACTION)) ... 
    通过上面的语句,响应“GridView”的点击事件。 
(06) if (action.equals(BT_REFRESH_ACTION)) ... 
    通过上面的语句,响应“按钮(bt_refresh)”的点击事件。

 

关于 “GridView”的点击事件。这里详细说明以下!

    像GridView这样的集合控件,不能单单像按钮一样,通过setOnClickPendingIntent() 来设置它的点击事件的Intent;而要通过以下两步来进行。 

    第一,设置GridView的点击响应事件的“Intent模板”。 
              这是通过 setPendingIntentTemplate() 来进行设置的。 
              这样做的目的有两个:首先, 设置Intent模板。 因为GridView有许多子项,它们这些子项都 统一 的要响应父亲的 Intent模板 。其次, 传递附件参数(例如,App Widget的ID) ,因为App Widget可以设置许多widget,每一个Widget的ID都不同,而且它们显示的内容可能不同(例如,不同大小的Widget显示不同大小的文字)。 
    第二, 设置GridView子项的点击响应事件的Intent。 
              设置通过 setOnClickFillInIntent() 来进行设置的。 
              这样做的首要目的,是 设置 GridView的子项所包含的信息 (例如,点击的 GridView子项的索引值 )。 
              通过这两步的设置之后,点击GridView中具体每一项的所产生的事件就是 “第一”和“第二”步中Intent的合集(组合) 。也就是说, 点击“GridView中某一个子项”所产生的Intent,同时包含了“通过 setPendingIntentTemplate 传递的Intent数据”和“通过 setOnClickFillInIntent 传递的Intent数据” 。 理解这一点对理解这个RemoteView的原理至关重要!!!

GridWidgetService.java的代码如下:

package com.skywang.test;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.content.Context;import android.content.Intent; import android.widget.RemoteViews; import android.widget.RemoteViewsService; import android.util.Log; import java.util.List; import java.util.ArrayList; import java.util.HashMap; public class GridWidgetService extends RemoteViewsService{ private static final String TAG = "SKYWANG"; @Override public RemoteViewsService.RemoteViewsFactory onGetViewFactory(Intent intent) { Log.d(TAG, "GridWidgetService"); return new GridRemoteViewsFactory(this, intent); } private class GridRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private Context mContext; private int mAppWidgetId; private String IMAGE_ITEM = "imgage_item"; private String TEXT_ITEM = "text_item"; private ArrayList
> data ; private String[] arrText = new String[]{ "Picture 1", "Picture 2", "Picture 3", "Picture 4", "Picture 5", "Picture 6", "Picture 7", "Picture 8", "Picture 9" }; private int[] arrImages=new int[]{ R.drawable.p1, R.drawable.p2, R.drawable.p3, R.drawable.p4, R.drawable.p5, R.drawable.p6, R.drawable.p7, R.drawable.p8, R.drawable.p9 }; /** * 构造GridRemoteViewsFactory * @author skywang */ public GridRemoteViewsFactory(Context context, Intent intent) { mContext = context; mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); Log.d(TAG, "GridRemoteViewsFactory mAppWidgetId:"+mAppWidgetId); } @Override public RemoteViews getViewAt(int position) { HashMap
map; Log.d(TAG, "GridRemoteViewsFactory getViewAt:"+position); // 获取 grid_view_item.xml 对应的RemoteViews RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.grid_view_item); // 设置 第position位的“视图”的数据 map = (HashMap
) data.get(position); rv.setImageViewResource(R.id.itemImage, ((Integer)map.get(IMAGE_ITEM)).intValue()); rv.setTextViewText(R.id.itemText, (String)map.get(TEXT_ITEM)); // 设置 第position位的“视图”对应的响应事件 Intent fillInIntent = new Intent(); fillInIntent.putExtra(GridWidgetProvider.COLLECTION_VIEW_EXTRA, position); rv.setOnClickFillInIntent(R.id.itemLayout, fillInIntent); return rv; } /** * 初始化GridView的数据 * @author skywang */ private void initGridViewData() { data = new ArrayList
>(); for (int i=0; i<9; i++) { HashMap
map = new HashMap
(); map.put(IMAGE_ITEM, arrImages[i]); map.put(TEXT_ITEM, arrText[i]); data.add(map); } } @Override public void onCreate() { Log.d(TAG, "onCreate"); // 初始化“集合视图”中的数据 initGridViewData(); } @Override public int getCount() { // 返回“集合视图”中的数据的总数 return data.size(); } @Override public long getItemId(int position) { // 返回当前项在“集合视图”中的位置 return position; } @Override public RemoteViews getLoadingView() { return null; } @Override public int getViewTypeCount() { // 只有一类 GridView return 1; } @Override public boolean hasStableIds() { return true; } @Override public void onDataSetChanged() { } @Override public void onDestroy() { data.clear(); } } }

说明: 

(01) public RemoteViewsService.RemoteViewsFactory onGetViewFactory(Intent intent) ... 
       通过上面的语句,返回一个RemoteViewsFactory对象。 
       RemoteViewsService是一个服务,通过之前对RemoteViewsService的介绍。我们知道,它 管理layout中集合视图的服务。 
       RemoteViewsService管理layout中集合视图的服务,是通过 RemoteViewsFactory 实现的;那么它是如何实现的呢? 
       RemoteViewsService是“通过 onGetViewFactory() 接口返回一个 RemoteViewsFactory 对象” 来实现的。 
(02) public void onCreate() ... 
       在onCreate()中进行 RemoteViewsFactory 的初始化工作 。 
(03) public int getCount() ... 
       通过getCount()返回 “集合视图”中的数据项的总数。 
(04) public RemoteViews getViewAt(int position) ... 
       通过上面的语句,返回 一个“集合视图”中具体每一项的视图。 
       getViewAt()是非常重要的函数! 我们对"集合视图"中每一项的初始化都是在getViewAt()中进行设置的 。 

grid_view_item.xml的代码如下:

点击下载: 

点击查看更多内容: 

1. 
2. 

实例效果图:

 

----------------------------------------------------------------------------------------------------

想做一个widget里面包含listview的复杂布局,于是查了些资料。整理了一下,形成自己的思路,把它写下来。第一次写,希望多给些意见。

我想先从我要实现的界面开始介绍起,请大家耐心读完它

 

首先是这样一个界面,这是在widget里面的布局,可以看到的是这个widget布局里面 有两部分需要处理,一是图标“花”点击之后应该有个动作,第二是如何处理listview的数据。而我要实现的是动态加载listview的数据,数据来源于数据库。

了解过widget的同学应该知道实现widget,首先需要重写AppWidgetProvider,而我们要实现listview还需要另外两个类, RemoteViewsService、 RemoteViewsFactory,准备好三个类之后才能进行下面详细的实施,至于这三者的作用我将会详细的介绍给大家。

1、RemoteViews 和AppWidgetProvider

RemoteViews翻译为远程试视图,是widget里面操作视图时必须用的,创建widget时,只需继承AppwidgetProvider,然后重写里面的Update就可以了。

像这样:

public class WidgetProvider extends AppWidgetProvider{
private AppWidgetManager appWidgetManager;  private int[] appWidgetIds; private Context context; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); } }
然后再onUpdate里面处理RemoteViews,下面具体根据我这个案例,介绍怎么处理Remoteviews
this.appWidgetIds = appWidgetIds;    this.appWidgetManager = appWidgetManager;  this.context = context; Timer timer = new Timer();//时时更新 timer.schedule(new TimerTask() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < WidgetProvider.this.appWidgetIds.length; i++)// appWidgetIds.length,表示创建了多少个widget { Intent ServiceIntent = new Intent(WidgetProvider.this.context, WidgetService.class); // 创建一个intent,启动WidgetService,WidgetService事继承的RemoteViewsService,返回一个RemoteViewsFactory ServiceIntent.putExtra(WidgetProvider.this.appWidgetManager.EXTRA_APPWIDGET_ID, WidgetProvider.this.appWidgetIds[i]); ServiceIntent.setData(Uri.parse(ServiceIntent.toUri(ServiceIntent.URI_INTENT_SCHEME))); // 设置uri,我不太清楚的地方是这边的uri是怎么获取到的,是根据刚开始new的时候得出的URI吗? RemoteViews widgetRemoteView = new RemoteViews(WidgetProvider.this.context .getPackageName(), R.layout.widget); widgetRemoteView.setRemoteAdapter(WidgetProvider.this.appWidgetIds[i], R.id.widget_content_list_view, ServiceIntent); // 走到这里大家应该可以看出处理Listview需要用SetRemoteAdapter,和ServiceIntent返回的值 Intent logoIntent = new Intent(WidgetProvider.this.context, MainActivity.class);// 设置点击的intent PendingIntent clickPendingIntent = PendingIntent.getActivity(WidgetProvider.this.context, 0, logoIntent, PendingIntent.FLAG_CANCEL_CURRENT); // 这边不知道干吗的?有懂的回复评论谢谢。 widgetRemoteView .setPendingIntentTemplate(R.id.widget_logo_image_view, clickPendingIntent);// 和楼上要结合使用 WidgetProvider.this.appWidgetManager.updateAppWidget(WidgetProvider.this.appWidgetIds[i], widgetRemoteView); } } }, 0, 1000);

   RemoteViewsService,是管理RemoteViews的服务。   

    一般,当App Widget 中包含“GridView、ListView、StackView等”集合视图时,才需要使用RemoteViewsService来进行更新、管理。(集合视图是指GridView、ListView、StackView等包含子元素的视图)   
    RemoteViewsService更新“集合视图”的一般步骤是:   
(01) 通过setRemoteAdapter来设置 “RemoteViews对应RemoteViewsService”。   
(02) 之后在RemoteViewsService中,实现RemoteViewsFactory接口。然后,在RemoteViewsFactory接口中对“集合视图”的各个子项进行设置(“集合视图”的各个子项:例如,GridView的每一个格子都是一个子项;ListView中的每一列也是一个子项)。 

2、 
RemoteViewsService

上述代码已经介绍了,我下面把例子贴给大家

public class WidgetService extends RemoteViewsService{ @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { // TODO Auto-generated method stub return new WidgetFactory(this,intent); } }
可以看到的是,所有的数据处理都在factory,那下面就来进行数据处理的过程

3、RemoteViewsFactory

    RemoteViewsFactory是RemoteViewsService中的一个接口。RemoteViewsFactory提供了一系列的方法管理“集合视图”中的每一项。例如:   

(01)RemoteViews getViewAt(int position)   
      通过getViewAt()来获取“集合视图”中的第position项的视图,视图是以RemoteViews的对象返回的。   
(02)int getCount()   
      通过getCount()来获取“集合视图”中所有子项的总数。

大家只需关注以上两个函数,例子代码中的其他函数基本功能都是获取数据,至于如何获取,请大家认真开代码和注解

import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import android.content.Context;import android.content.Intent; import android.database.Cursor; import android.widget.RemoteViews; import android.widget.RemoteViewsService.RemoteViewsFactory; public class WidgetFactory implements RemoteViewsFactory { private Context context; private int appwidgetId; private Cursor cursor; private int[] typeImageViews = {R.drawable.metting_menu, R.drawable.memo_menu, R.drawable.memorialday_menu, R.drawable.todo_menu}; private String timeAndAdressStrings; private String titleStrings; private String TIMEANDADRESS = "timeAndAdress"; private String TITLE = "title"; private String TYPE = "type"; private ArrayList
> data; private MyDatabaseHelper myDatabaseHelper; public WidgetFactory(Context context, Intent intent) { // TODO Auto-generated constructor stub this.context = context; this.cursor = WidgetData.QueryData(context); myDatabaseHelper = new MyDatabaseHelper(context, 1); } @Override public void onCreate() { // TODO Auto-generated method stub InitListViewData(); } // 初始化DATA private void InitListViewData() { data = new ArrayList
>(); cursor.moveToFirst(); for (int i = 0; i < cursor.getCount(); i++) { HashMap
map = new HashMap
(); String timeString = cursor.getString(cursor.getColumnIndex(myDatabaseHelper.time)); String adressString = cursor.getString(cursor.getColumnIndex(myDatabaseHelper.adress)); String titleString = cursor.getString(cursor.getColumnIndex(myDatabaseHelper.title)); //将数据库数据全部取出来,生成字符的形式 int type = cursor.getInt(cursor.getColumnIndex(myDatabaseHelper.typeid)); timeAndAdressStrings = timeString + "," + adressString; titleStrings = titleString; map.put(TIMEANDADRESS, timeAndAdressStrings); map.put(TITLE, titleStrings); map.put(TYPE, type); data.add(map);//用hashmap处理数据,再在getviewAt中处理hashmap的数据 } } @Override public void onDataSetChanged() { // TODO Auto-generated method stub } @Override public void onDestroy() { // TODO Auto-generated method stub data.clear(); } @Override public int getCount() { // TODO Auto-generated method stub return cursor.getCount(); } @Override public RemoteViews getViewAt(int position) { // TODO Auto-generated method stub HashMap
map; RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_listview_single_item);//获取item的视图 map = data.get(position);//获取数据 remoteViews.setImageViewResource(R.id.widget_single_list_view_item_type_image_view, typeImageViews[(Integer) map.get(TYPE)]); remoteViews.setTextViewText(R.id.widget_single_view_item_time_and_adress_text_view, (CharSequence) map.get(TIMEANDADRESS)); remoteViews.setTextViewText(R.id.widget_single_view_item_title_text_view, (CharSequence) map.get(TITLE));//处理数据 return remoteViews; } @Override public RemoteViews getLoadingView() { // TODO Auto-generated method stub return null; } @Override public int getViewTypeCount() { // TODO Auto-generated method stub return 1; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override

转载于:https://www.cnblogs.com/jichengwang/p/4257275.html

你可能感兴趣的文章
[BZOJ2667][cqoi2012]模拟工厂
查看>>
java EE设计模式--spring企业级开发最佳实践文摘
查看>>
实验6 数组一
查看>>
课堂作业05
查看>>
HTML基础2
查看>>
冒泡排序的两种实现
查看>>
boa web服务器
查看>>
将博客搬至CSDN
查看>>
AngularJS ng-model在ng-if里面无效
查看>>
今天2019年5月,21点58分
查看>>
JavaScript_几种创建对象(2017-07-04)
查看>>
类的初始化
查看>>
centos 7 install eclipse cdt and use github
查看>>
android自定义键盘光标不显示解决方法
查看>>
第一章 大型网站架构演化
查看>>
java基础<迷你DVD系统>
查看>>
NO.6LINUX基本命令
查看>>
MFC中 CDateTimeCtrl 自定义日期显示格式
查看>>
冒泡排序、选择排序、插入排序
查看>>
java--多线程之Thread继承
查看>>