本章主要介绍ListView的使用方法,各种Adapter,例如ArrayAdapter、SimpleCursorAdapter、SimpleAdapter、BaseAdapter,

以及ContentProvider的介绍、Cursor的使用,PackageManager查找应用信息的方法。

现在很多应用都要用到ListView来做列表显示,例如微信的聊天列表、音乐播放器的列表、邮件列表等等。

由于测试时需要一些数据,所以先讲下PackageManager,等会将手机上的应用名称用ListView显示出来。

PackageManager pm = (PackageManager)getPackageManager();
//通过PackageManager可以获取到应用的所有信息
abstract ApplicationInfo     getApplicationInfo(String packageName, int flags)
abstract PackageInfo     getPackageInfo(String packageName, int flags)
abstract ListgetInstalledApplications(int flags)
abstract ListgetInstalledPackages(int flags)
abstract ListqueryIntentActivities(Intent intent, int flags)
ApplicationInfo    //通过它可以获取应用的图标ICON,以及软件名
Drawable     loadIcon(PackageManager pm)
CharSequence     loadLabel(PackageManager pm)
//另外,通过ApplicationInfo的成员flags可以知道此应用是否为系统应用:
//if(mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM == 0) 那么说明此应用不是系统应用
PackageInfo        //通过它可以获取包名、权限、版本、更新时间
//以下是PackageInfo的public成员,可以直接使用:
public String   packageName
public PermissionInfo[] permissions
public int  versionCode
public long firstInstallTime
public long lastUpdateTime
ResolveInfo        //通过它可以获取图标ICON、软件名,以及包名
Drawable     loadIcon(PackageManager pm)
CharSequence     loadLabel(PackageManager pm)
//以下的ActivityInfo的public成员,通过ActivityInfo的packageName成员获取包名
public ActivityInfo activityInfo

使用ListView显示内容,需要准备一个包含ListView的layout文件以及一个Adapter,这个adapter的作用是将每条数据显示到ListView中

构造adapter的时候,需要准备一个List数据源以及一个layout布局文件,即数据如何展示。

ArrayAdapter

布局文件里只能有一个TextView,显示内容只能是String类型的

SimpleCursorAdapter

从ContentProvider里用Cursor取每条记录(记录里包含多个数据),布局文件可以包含多个View,可以指定哪个数据与哪个View关联

SimpleAdapter

数据来源不限,通常放在List<HashMap<String,Object>>里,布局文件自由,可以指定HashMap里哪个String与布局里哪个id关联,与ImageView关联的Object为Drawable类型,与TextView关联的Object为String类型,与CheckBox关联的Object为boolean类型。

BaseAdapter

用起来没有SimpleAdapter简洁,不过BaseAdapter最自由,需要重写getView方法,这个getView会传递进来position参数,返回View.

在getView里,将layout布局文件inflate后,可以任意地将各种数据显示到布局里的各种View上,另外还可以指定OnClickListener

OK,接下来开始研究ListView中最简单的ArrayAdapter:

我们想要将手机上的所有软件通过ListView列出来,当点击某一项时,能够显示第几项被点击。下图是演示效果

主界面的layout文件如下,activity_main.xml

接下来创建一个layout文件,list.xml,它用于展示ListView里的每一行,供ArrayAdapter使用的layout只能包含一个TextView,内容如下:
主程序通过PackageManager获取安装的所有软件的名字,然后存到ArrayList<String>里,然后构造一个ArrayAdapter,将ArrayList<String>数据与list布局文件绑定起来。最后通过ListView的setAdapter方法来指定它的Adapter,这里使用之前构造的ArrayAdapter,另外再为这个ListView设置一个ItemClickListener,代码如下:
package com.example.listview;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private final String TAG = "ListViewTest";
private ListView mListView;
private TextView mTextView;
private PackageManager mPackageManager;
private ArrayListmPackages;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPackageManager = (PackageManager)getPackageManager();
mListView = (ListView)findViewById(R.id.list);
mTextView = (TextView)findViewById(R.id.hello);
mPackages = new ArrayList();
Listapps = mPackageManager.getInstalledApplications(0);
for(ApplicationInfo info:apps){
mPackages.add("软件名:" + info.loadLabel(mPackageManager) + " 包名:" + info.packageName);
}
Log.d(TAG, "size: " + mPackages.size());
ArrayAdapter adapter = new ArrayAdapter(this, R.layout.list, mPackages);
mListView.setAdapter(adapter);
mListView.setOnItemClickListener(mListener);
}
private OnItemClickListener mListener = new OnItemClickListener(){
public void onItemClick(AdapterView parent,View v,int position,long id){
mTextView.setText("Item " + position + " clicked");
}
};
}

接下来,我们使用SimpleCursorAdapter将联系人的姓名和电话号码通过ListView显示出来。在此之前先来讲下Cursor的使用。

ContentProvider管理着一组数据,一般使用数据库的方式存储,它提供了标准接口,用于其它应用程序来访问这些数据。例如联系人、短信、settings、手机上的图片、视频等等内容。一般我们通过ContentResolver.query方式来获取某个Content Provider提供的内容。在我们的应用程序里,这个ContentResolver可以通过getContentResolver来得到。

final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

下面代码演示了query的用法,各参数的作用,以及Cursor的含义:

Uri uri = Uri.parse("content://contacts/people");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
int cnt = cursor.getCount();
int ColumnCnt = cursor.getColumnCount();
Log.d(TAG,"cursor cnt: " + cursor.getCount());
Log.d(TAG,"column cnt: " + ColumnCnt);
for(int i=0; i < ColumnCnt; i++){
Log.d(TAG,"column " + i + " name: " + cursor.getColumnName(i));
}
cursor.moveToFirst();
for(int i=0; i < cnt; i++){
Log.d(TAG, "姓名: " + cursor.getString(10) + " 电话: " + cursor.getString(6));
cursor.moveToNext();
}
//以下是相关log,为了隐私,部分号码已被屏蔽
D/ListViewTest( 7937): cursor cnt: 18
D/ListViewTest( 7937): column cnt: 22
D/ListViewTest( 7937): column 0 name: times_contacted
D/ListViewTest( 7937): column 1 name: custom_ringtone
D/ListViewTest( 7937): column 2 name: primary_organization
D/ListViewTest( 7937): column 3 name: phonetic_name
D/ListViewTest( 7937): column 4 name: status
D/ListViewTest( 7937): column 5 name: label
D/ListViewTest( 7937): column 6 name: number
D/ListViewTest( 7937): column 7 name: type
D/ListViewTest( 7937): column 8 name: mode
D/ListViewTest( 7937): column 9 name: last_time_contacted
D/ListViewTest( 7937): column 10 name: display_name
D/ListViewTest( 7937): column 11 name: im_handle
D/ListViewTest( 7937): column 12 name: _id
D/ListViewTest( 7937): column 13 name: number_key
D/ListViewTest( 7937): column 14 name: starred
D/ListViewTest( 7937): column 15 name: primary_email
D/ListViewTest( 7937): column 16 name: name
D/ListViewTest( 7937): column 17 name: primary_phone
D/ListViewTest( 7937): column 18 name: im_account
D/ListViewTest( 7937): column 19 name: notes
D/ListViewTest( 7937): column 20 name: im_protocol
D/ListViewTest( 7937): column 21 name: send_to_voicemail
D/ListViewTest( 7937): 姓名: 千结构 电话: 187****6831
D/ListViewTest( 7937): 姓名: 老马 电话: 135****1222
D/ListViewTest( 7937): 姓名: 刘元涛 电话: 139****9412
D/ListViewTest( 7937): 姓名: 元 电话: 153****1111
D/ListViewTest( 7937): 姓名: 延政 电话: +86158****2793
D/ListViewTest( 7937): 姓名: 田总 电话: 139****3706
D/ListViewTest( 7937): 姓名: 杨哥 电话: 134****9742
D/ListViewTest( 7937): 姓名: 瞿手板 电话: 138****2335
D/ListViewTest( 7937): 姓名: 曹宏 电话: 1866582****
D/ListViewTest( 7937): 姓名: felix 电话: 1801868****
D/ListViewTest( 7937): 姓名: 黑狗 电话: 1377298****
D/ListViewTest( 7937): 姓名: 延治 电话: 1599144****
D/ListViewTest( 7937): 姓名: 鸿运 电话: 1322704****
D/ListViewTest( 7937): 姓名: 潘工 电话: 1353034****
D/ListViewTest( 7937): 姓名: 何群创 电话: 1582078****
D/ListViewTest( 7937): 姓名: 艳萍 电话: 1881755****
D/ListViewTest( 7937): 姓名: 贺工 电话: 1391707****
D/ListViewTest( 7937): 姓名: 陶望标 电话: +861376100****
注意读取联系人要加权限:<uses-permission android:name="android.permission.READ_CONTACTS"/>

从代码可以看出,使用query去获取数据的时候,需要指定uri,即指定从哪个ContentProvider来取。关于后面的几个参数,等下再介绍。获取到的结果其实是一个表,这个Cursor指向了其中的某一项,通过Cursor.moveToFirst将光标指向第一项,Cursor.moveToNext将光标指向下一项。总共有多少项结果,可以通过Cursor.getCount获得。Cursor.getColumnCount得到的是列数,以上代码不加筛选条件时,返回的列数有22列,例如每个联系人都有姓名(display_name 第10列)、电话(number 第6列)、联系次数(times_contacted 第0列)、最后一次联系时间(last_time_contacted 第9列)获取当前cursor指向这个人的某列数据,可以通过cursor.getString(int columnIndex)、cursor.getDouble(int columnIndex)、cursor.getLong(int columnIndex),具体某列的数据类型可以通过cursor.getType(int columnIndex)获知,其返回值为int类型,FIELD_TYPE_STRING(值为3)、FIELD_TYPE_INTEGER(值为1)、FIELD_TYPE_FLOAT(值为2)

接下来研究下query里的几个参数具体含义和用法。其中projection即选择那些列,它是"列名"的String类型数组,你需要提前知道指定ContentProvider提供的每列的名字(通过cursor.getColumnName(int columnIndex)获得),否则你就不知道你要筛选哪些数据了。当然,如果写null,则返回所有。selection和selectionArgs用来选择哪些行,比如选择电话号码以139开头的联系人(number LIKE '139%'),注意LIKE的左右要留有空格,两个单引号不能省,其中的%表示通配符。如果希望电话号码包含有2953,可以用'%2953%',另外如果selection里包含多个?符号,那么会用selectionArgs里的String数组来替换。sortOrder用来对结果排序。

Uri uri = Uri.parse("content://contacts/people");
Cursor cursor = getContentResolver().query(uri, new String[]{"display_name","number"},
"number"+" LIKE "+"'139%'", null, null);
int cnt = cursor.getCount();
int ColumnCnt = cursor.getColumnCount();
Log.d(TAG,"cursor cnt: " + cursor.getCount());
Log.d(TAG,"column cnt: " + ColumnCnt);
for(int i=0; i < ColumnCnt; i++){
Log.d(TAG,"column " + i + " name: " + cursor.getColumnName(i));
}
cursor.moveToFirst();
for(int i=0; i < cnt; i++){
Log.d(TAG, "姓名: " + cursor.getString(0) + " 电话: " + cursor.getString(1));
cursor.moveToNext();
}
D/ListViewTest(25584): cursor cnt: 4
D/ListViewTest(25584): column cnt: 2
D/ListViewTest(25584): column 0 name: display_name
D/ListViewTest(25584): column 1 name: number
D/ListViewTest(25584): 姓名: 老贾 电话: 1392*******
D/ListViewTest(25584): 姓名: 刘元涛 电话: 1391*******
D/ListViewTest(25584): 姓名: 田总 电话: 1390*******
D/ListViewTest(25584): 姓名: 贺工 电话: 1391*******

注意到筛选后,只获得4个联系人,而且列数只有2项,cursor.getString(0)返回的就是名字,cursor.getString(1)返回的就是号码,它其实就是和projection里的数组顺序相对应的。

Uri uri = Uri.parse("content://contacts/people");
Cursor cursor = getContentResolver().query(uri, new String[]{"display_name","number","times_contacted"},
"display_name=?" + " OR " + "number=?", new String[]{"贺工","15319861111"}, null);
int cnt = cursor.getCount();
int ColumnCnt = cursor.getColumnCount();
Log.d(TAG,"cursor cnt: " + cursor.getCount());
Log.d(TAG,"column cnt: " + ColumnCnt);
for(int i=0; i < ColumnCnt; i++){
Log.d(TAG,"column " + i + " name: " + cursor.getColumnName(i));
}
cursor.moveToFirst();
for(int i=0; i < cnt; i++){
Log.d(TAG, "姓名: " + cursor.getString(0) + " 电话: " + cursor.getString(1) + " 次数: " + cursor.getInt(2));
cursor.moveToNext();
}
D/ListViewTest( 1252): cursor cnt: 2
D/ListViewTest( 1252): column cnt: 3
D/ListViewTest( 1252): column 0 name: display_name
D/ListViewTest( 1252): column 1 name: number
D/ListViewTest( 1252): column 2 name: times_contacted
D/ListViewTest( 1252): 姓名: 元 电话: 15319861111 次数: 41
D/ListViewTest( 1252): 姓名: 贺工 电话: 13917077026 次数: 0

关于ContentProvider就介绍到这里,除了联系人,还有短信收件箱"content://sms/inbox"、安全设置"content://settings/secure"等等。

接下来就可以利用SimpleCursorAdapter来将联系人信息显示到ListView上,效果如下:

主界面的layout文件activity_main.xml和之前一样,来看下用于显示每行的layout文件list.xml

这个layout文件包含有两个TextView,id分别为name、number,用于显示每个联系人的姓名和电话

SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)

构造SimpleCursorAdapter时,需要提供用于显示每行的layout,数据源cursor,

以及将cursor里的哪个column(使用column name)显示到哪个view上(使用view的id)代码如下:

package com.example.listview;
import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
public class MainActivity extends Activity {
private final String TAG = "ListViewTest";
private TextView mTextView;
private ListView mListView;
private Cursor mCursor;
private SimpleCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.hello);
mListView = (ListView)findViewById(R.id.list);
mCursor = getContentResolver().query(Uri.parse("content://contacts/people"),
null,null,null,null);
mAdapter = new SimpleCursorAdapter(this, R.layout.list, mCursor,
new String[]{"display_name","number"}, new int[]{R.id.name,R.id.number});
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(mListener);
}
private OnItemClickListener mListener = new OnItemClickListener(){
@Override
public void onItemClick(AdapterView parent,View v,int position,long id){
mTextView.setText("Item " + position + " clicked");
}
};
}

可以看到,使用起来还是很简单的,只要将cursor里column与layout里id关联起来,剩下的就由adapter自动完成。

由于ArrayAdapter只能用于显示单个String数据,而SimpleCursorAdapter只能从Cursor取数据,所以使用场合受到了一定的限制,接下来介绍下SimpleAdapter,它的数据来源不受限制(String、Drawable、Boolean等),而且layout文件里的View也可以很丰富(TextView、ImageView、CheckBox等),SimpleAdapter的构造方法如下:

SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

我们可以从多种渠道获取数据,然后放到一个List<HashMap<String, Object>>里,

通过SimpleAdapter将数据源List里的每个HashMap数据显示到ListView里的每一行。参数resouce就是用于显示每一行的layout。

HashMap里存放的是多个String-Object,例如("name" - "taiwan","picture" - Drawable数据,"male" - true)

SimpleAdapter里的参数String[] from就是HashMap里的String,而int[] to就是layout文件里每个View的id,

注意String和id的对应顺序,与CheckBox对应的Object只能时Boolean类型。

OK,接下来我们要实现将手机安装的所有APP列出来,内容包括图标、软件名、包名、以及一个CheckBox,

当点击某一行时,对应的CheckBox可以被勾上或撤销,效果如下图:

主界面只包含一个ListView,这个很简单,我们来看下用于显示每一行的layout文件 list.xml

注意CheckBox的这条属性android:focusable="false",因为CheckBox占据了焦点,所以ListView里每一行无法响应点击事件,因此要将focusable置为false

下面是SimpleAdapter的用例代码:
package com.example.listview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class MainActivity extends Activity {
private final String TAG = "ListViewTest";
private ListView mListView;
private PackageManager mManager;
private SimpleAdapter mAdapter;
private List>mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mManager = (PackageManager)getPackageManager();
Listapps = mManager.getInstalledApplications(0);
Log.d(TAG,"app size: " + apps.size());
mList = new ArrayList>(); for(ApplicationInfo info:apps){ HashMap map = new HashMap (); map.put("icon", info.loadIcon(mManager)); map.put("lable", info.loadLabel(mManager)); map.put("name", info.packageName); map.put("check", false); mList.add(map); } mListView = (ListView)findViewById(R.id.list); mAdapter = new SimpleAdapter(this, mList, R.layout.list, new String[]{"icon","lable","name","check"}, new int[]{R.id.icon, R.id.lable, R.id.name, R.id.check}); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(mListener); } private OnItemClickListener mListener = new OnItemClickListener(){ @Override public void onItemClick(AdapterView parent,View v,int position,long id){ if(((Boolean)(mList.get(position).get("check"))).booleanValue() == false) mList.get(position).put("check", true); else mList.get(position).put("check", false); mAdapter.notifyDataSetChanged(); //通知数据源已更新,需要刷新ListView Log.d(TAG,"check: " + position); } }; } 

首先通过PackageManager获得安装的所有应用,然后将每个应用的图标(Drawable)、应用名(String)、包名(String)、与应用对应的CheckBox(Boolean)存储到HashMap里,然后构造一个SimpleAdapter,为其指定数据源、layout、以及HashMap里数据与layout里id的对应关系,

另外要注意下HashMap里的String并不需要和layout里的id同名,我这里偷懒所以写的相同的名字:)

接下来由SimpleAdapter读取数据源的数据,然后将其显示到ListView里,这个过程自动完成。

当点击某一行时,我们修改mList里对应HashMap里的"check"数据,此时需要调用Adapter的notifyDataSetChanged方法,来通知ListView刷新。

这个SimpleAdapter用起来是不是很自由?很简单?不过我们做的时候会发现:1. 图片没有显示出来 2. CheckBox状态混乱

图片没有显示出来是因为SimpleAdapter将Drawable类型的Object显示到View上时遇到问题,可以通过setViewBinder来解决,代码如下:

       mAdapter.setViewBinder(new ViewBinder(){
public boolean setViewValue(View view,Object data,String text){
if(view instanceof ImageView && data instanceof Drawable){
ImageView v = (ImageView)view;
v.setImageDrawable((Drawable)data);
return true;
}else{
return false;
}
}
});

CheckBox状态问题,是由于CheckBox本身就能响应click事件并做出勾选或撤销动作,这个功能对我们来说没有用处,因为CheckBox的状态由HashMap里的check参数决定,因此需要将CheckBox的click禁止掉,修改list.xml,给CheckBox添加 android:clickable="false"属性

实验之后,我们发现列出来了上百个记录,如果我们只想列出来在桌面上能够被启动的APP的话,可以使用PackageManager的queryIntentActivities方法来获取应用。

完整代码如下:

package com.example.listview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;
public class MainActivity extends Activity {
private final String TAG = "ListViewTest";
private ListView mListView;
private PackageManager mManager;
private SimpleAdapter mAdapter;
private List>mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mManager = (PackageManager)getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);   //可以在桌面启动的APP
Listapps = mManager.queryIntentActivities(intent, 0);
Log.d(TAG,"app size: " + apps.size());
mList = new ArrayList>(); for(ResolveInfo info:apps){ HashMap map = new HashMap (); map.put("icon", info.loadIcon(mManager)); map.put("lable", info.loadLabel(mManager)); map.put("name", info.activityInfo.packageName); map.put("check", false); mList.add(map); } mListView = (ListView)findViewById(R.id.list); mAdapter = new SimpleAdapter(this, mList, R.layout.list, new String[]{"icon","lable","name","check"}, new int[]{R.id.icon, R.id.lable, R.id.name, R.id.check}); mAdapter.setViewBinder(new ViewBinder(){ public boolean setViewValue(View view,Object data,String text){ if(view instanceof ImageView && data instanceof Drawable){ ImageView v = (ImageView)view; v.setImageDrawable((Drawable)data); return true; }else{ return false; } } }); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(mListener); } private OnItemClickListener mListener = new OnItemClickListener(){ @Override public void onItemClick(AdapterView parent,View v,int position,long id){ if(((Boolean)(mList.get(position).get("check"))).booleanValue() == false) mList.get(position).put("check", true); else mList.get(position).put("check", false); mAdapter.notifyDataSetChanged(); //通知数据源已更新,需要刷新ListView Log.d(TAG,"check: " + position); } }; } 

另外还可以通过(ApplicationInfo)info.flags & ApplicationInfo.FLAG_SYSTEM来判断是否为系统APP。

BaseAdapter自由度更大,不过稍显麻烦一点,需要自己去实现将data画到view上去。还是用那个显示APP的例子,这次加上一个按钮,当点击按钮时,使用Toast显示对应的应用名,效果如下:

以下是这个例子的layout文件list.xml


使用BaseAdapter的范例代码如下:

package com.example.listview;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private final String TAG = "ListViewTest";
private ListView mListView;
private PackageManager mManager;
private MyAdapter mAdapter;
private List>mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mManager = (PackageManager)getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
Listapps = mManager.queryIntentActivities(intent, 0);
Log.d(TAG,"app size: " + apps.size());
mList = new ArrayList>(); for(ResolveInfo info:apps){ HashMap map = new HashMap (); map.put("icon", info.loadIcon(mManager)); map.put("lable", info.loadLabel(mManager)); map.put("name", info.activityInfo.packageName); map.put("check", false); mList.add(map); } mListView = (ListView)findViewById(R.id.list); mAdapter = new MyAdapter(this); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(mListener); } private class MyAdapter extends BaseAdapter{ private Context mContext; public MyAdapter(Context context){ mContext = context; } @Override public int getCount() { // TODO Auto-generated method stub return mList.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return mList.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } public class MyView{ private ImageView mImage; private TextView mLable; private TextView mPackage; private CheckBox mCheck; private Button mButton; } @Override public View getView(int position, View v, ViewGroup parent) { // TODO Auto-generated method stub MyView view = null; HashMap map = mList.get(position); if(v == null){ v = LayoutInflater.from(mContext).inflate(R.layout.list, null); view = new MyView(); view.mImage = (ImageView)v.findViewById(R.id.icon); view.mLable = (TextView)v.findViewById(R.id.lable); view.mPackage = (TextView)v.findViewById(R.id.name); view.mCheck = (CheckBox)v.findViewById(R.id.check); view.mButton = (Button)v.findViewById(R.id.button); v.setTag(view); }else view = (MyView)v.getTag(); view.mImage.setImageDrawable((Drawable)map.get("icon")); view.mLable.setText((String)map.get("lable")); view.mPackage.setText((String)map.get("name")); if((Boolean)map.get("check")) view.mCheck.setChecked(true); else view.mCheck.setChecked(false); view.mButton.setOnClickListener(new MyListener(position)); return v; } public class MyListener implements OnClickListener{ private int mPosition; public MyListener(int position){ mPosition = position; } @Override public void onClick(View v){ Log.d(TAG,"click id: " + mPosition); Toast.makeText(getApplicationContext(), "应用: " + mList.get(mPosition).get("lable"), Toast.LENGTH_SHORT).show(); } } } private OnItemClickListener mListener = new OnItemClickListener(){ @Override public void onItemClick(AdapterView parent,View v,int position,long id){ if(((Boolean)(mList.get(position).get("check"))).booleanValue() == false) mList.get(position).put("check", true); else mList.get(position).put("check", false); mAdapter.notifyDataSetChanged(); //通知数据源已更新,需要刷新ListView Log.d(TAG,"check: " + position); } }; } 

最关键的就是继承BaseAdapter,然后重写getView方法,根据传递进来的position,从mList里取出HashMap数据,然后inflate布局文件list.xml,将map里的数据画到view上。

Button也可以添加OnClickListener事件,由于每个Button要记录自己所在的postion,所以这里构造了一个MyListener类。

Android ListView完全解析相关推荐

  1. #周末课堂# 赵扬老师 Android系列课程【ListView完全解析、Memory in Android】(火热报名中~~~)...

    课程名称: 课程一: Android晋级系列讲座之ListView完全解析(中级课程) 课程二: Memory in Android(高级课程) 讲师资料:      讲师 - 赵杨 - Androi ...

  2. Android ListView工作原理完全解析,带你从源码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是List ...

  3. Android MVP模式 解析JSON 显示到ListView上

    Android MVP模式 解析JSON 显示到ListView上 有关MVP模式的介绍,这里不作详细解释,稍后会更新MVP设计模式,请等待链接-- 简述本次的主要功能实现: 通过mvp设计模式,(M ...

  4. 【腾讯Bugly干货分享】Android ListView与RecyclerView对比浅析--缓存机制

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d... 作者:黄宁源 一,背景 RecyclerView是谷歌官方出的一 ...

  5. Android ListView异步加载图片乱序问题,原因分析及解决方案

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android所有系统自带的控件当中,ListView这个控件算是 ...

  6. Android源码解析--AlertDialog及AlertDialog.Builder

    昨天晚上弄到很晚,简单的看了下Dialog的源码,说要分析下建造者模式,在dialog里面的应用其实是在AlertDialog中. 按照惯例,先看类说明: [java] view plaincopy ...

  7. android listview动态加载网络图片不显示,Android Listview异步动态加载网络图片

    Android Listview异步动态加载网络图片 详见: http://blog.sina.com.cn/s/blog_62186b460100zsvb.html 标签: Android SDK ...

  8. Android ListView 实现下拉刷新上拉加载

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/39965327 1.简介 无疑,在Android开发中,ListView是使用非常频 ...

  9. android listview网络图片,Android ListView从网络获取图片及文字显示

    上一篇文章说的是ListView展示本地的图片以及文本,这一篇说一下如何从网络获取图片以及文本来显示.事实上,一般是先获取Josn或sml数据,然后解释显示.我们先从网上获取xml,然后对其进行解析, ...

最新文章

  1. Spring使用外部属性文件
  2. laravel5.6 php,Laravel5.6中的队列简单使用
  3. php 输出 jsonp
  4. 数据库周刊 | DBA 核心技能
  5. Python定义函数及引用
  6. 某绒面试的病毒分析(一)
  7. Magnet for mac(专业窗口辅助工具)支持m1
  8. copy的过去式_copy的过去式和用法例句
  9. 中英文标点符号切换的组合键_切换中英文标点快捷键
  10. java 熄灯问题_C++基础算法学习——熄灯问题
  11. 多维泰勒网matlab,非线性定常系统的多维泰勒网优化跟踪控制
  12. 家长们,居家网课这样做
  13. 【绝对干货】kafka偏移量设置
  14. [敛火成丹]Win11Dev-25236.1010专业工作站版-微调
  15. Vmware搭建软路由教程(Openwrt)
  16. Emgucv使用中常用函数总结
  17. JS中使用bignumber处理高精度小数 失去去精确度运算 bigNumber用法
  18. 友推微信分享失败解决办法
  19. 触摸传感器PCB布局设计指南(二)
  20. 基于op07的k型热电偶测量电路_k型热电偶测温电路图解析

热门文章

  1. Intel-Joule-570x刷板记录
  2. 运行程序时出现“NotSerializableException”解决方法
  3. 55——SPNet: A novel deep neural network for retinal vessel segmentation basedon shared decoder and p
  4. ChatGPT介绍与理解
  5. 启动weblogic时报错: java.lang.NoClassDefFoundError: weblogic/Server
  6. xp系统打开itunes显示服务器失败,win7系统打开iTunes显示Apple Mobile Device Service无法启动怎么解决...
  7. 数字化工厂的定义是什么?如何看待数字化工厂的发展?
  8. Yarn Workspace 使用指南
  9. UGUI-- Text文本控件
  10. 【drawio笔记】禁用组大小调整