Android开发系列之ListView
上篇博客解决了Android客户端通过WebService与服务器端程序进行交互的问题,这篇博客重点关注两个问题,一个是Android应用程序如何与本机文件型数据库SQLite进行交互,另一问题则是如何在ListView中按照我们想要的界面效果进行展示。限于篇幅这篇重点讲ListView,下篇博客重点阐述SQLite。
ListView是一个常用的数据显示控件,假设我们要做一个简单的界面,如图所示。



这张图是我直接从Android平板电脑(Android 4.2.2)上面截图下来的,就是一个普通的列表,能够点击报名按钮获取到对应行的信息。
这里面显示的数据是我从SQLite数据库中查询出来的,封装的类的代码如下:
- public class MyDatabaseHelper extends SQLiteOpenHelper {
- private static final String name = "mydb.db";// SQLite数据库文件名
- private static final int version = 1;// SQLite数据库版本号
- public MyDatabaseHelper(Context context) {
- super(context, name, null, version);
- }
- @SuppressLint("SimpleDateFormat")
- @Override
- public void onCreate(SQLiteDatabase db) {
- try {
- // 开启事务
- db.beginTransaction();
- String sql = "create table jobInfo (name varchar(20),"
- + "num integer," + "date varchar(10),"
- + "description text)";
- db.execSQL(sql);
- //测试插入10条数据
- for (int i = 0; i < 10; i++) {
- db.execSQL(
- "insert into jobInfo(name,num,date,description)values(?,?,?,?)",
- new Object[] {
- "name" + i,
- i,
- new SimpleDateFormat("yyyy-MM-dd")
- .format(new Date()), "description" + i });
- }
- // 标识事务成功
- db.setTransactionSuccessful();
- } finally {
- // 结束事务
- db.endTransaction();
- }
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- //数据库升级操作
- }
- }
在需要创建数据库、插入数据的地方都可以实例化MyDatabaseHelper这个类,关于更多的SQLite的细节下篇博客将会进行详细的说明。
activity_main.xml布局文件:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin" >
- <LinearLayout
- android:id="@+id/head"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="岗位名称"
- android:textSize="24sp"
- android:width="150dip" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="岗位数量"
- android:textSize="24sp"
- android:width="150dip" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="发布日期"
- android:textSize="24sp"
- android:width="150dip" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="岗位描述"
- android:textSize="24sp"
- android:width="550dip" />
- </LinearLayout>
- <ListView
- android:id="@id/android:list"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/head" >
- </ListView>
- </RelativeLayout>
可以看到这是一个相对布局,里面有一个线性布局,线性布局里面又放置了4个TextView作为ListView数据的标题。下面直接是一个ListView控件,由于这是相对布局,为了让ListView显示在“表头”下面,我们设置了layout_below属性。此外要注意ListView的id的写法。
接着按照界面的要求,我们准备一下ListView加载布局文件的内容,我们起名为:list_item.xml。
list_item.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
- <TextView
- android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="24sp"
- android:width="150dip" />
- <TextView
- android:id="@+id/num"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="24sp"
- android:width="150dip" />
- <TextView
- android:id="@+id/date"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="24sp"
- android:width="150dip" />
- <TextView
- android:id="@+id/description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="24sp"
- android:width="550dip" />
- <Button
- android:id="@+id/btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="false"
- android:focusableInTouchMode="false"
- android:text="报名"
- android:width="150dip"
- android:textSize="24sp" />
- </LinearLayout>
这也是一个普通的线性布局,设置orientation为horizontal(水平)。
布局文件准备好,下面我们准备写代码了。
我们让MainActivity这个类继承自ListActivity,完整的代码如下:
- public class MainActivity extends ListActivity {
- List<Map<String, Object>> list;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- list = new ArrayList<Map<String, Object>>();
- //初始化SQLite数据库操作类对象
- MyDatabaseHelper dbHelper = new MyDatabaseHelper(MainActivity.this);
- //查询数据库返回Cursor(游标)对象
- Cursor cursor = dbHelper.getReadableDatabase().query("jobInfo",
- new String[] { "name", "num", "date", "description" }, null,
- null, null, null, "name");
- //将结果集封装到List<Map<String,Object>>数据结构当中
- while (cursor.moveToNext()) {
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("name", cursor.getString(0));
- map.put("num", cursor.getInt(1));
- map.put("date", cursor.getString(2));
- map.put("description", cursor.getString(3));
- map.put("btn", R.drawable.ic_launcher);
- list.add(map);
- }
- //查询完毕,记得及时关闭数据库链接
- cursor.close();
- MyButtonAdapter adapter = new MyButtonAdapter(MainActivity.this, list,
- R.layout.list_item, new String[] { "name", "num", "date",
- "description", "btn" }, new int[] { R.id.name,
- R.id.num, R.id.date, R.id.description, R.id.btn });
- //给ListView设置数据填充适配器
- ListView listView = (ListView) findViewById(android.R.id.list);
- listView.setAdapter(adapter);
- }
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- //ListView的
- @SuppressWarnings("unchecked")
- Map<String, Object> map = (HashMap<String, Object>) l
- .getItemAtPosition(position);
- Toast.makeText(MainActivity.this,
- "您点击了:" + map.get("name").toString() + "岗位!",
- Toast.LENGTH_SHORT).show();
- }
- public class MyButtonAdapter extends BaseAdapter {
- private class ButtonViewHolder {
- TextView name;
- TextView num;
- TextView date;
- TextView description;
- Button btn;
- }
- private Context mContext;
- private List<Map<String, Object>> mList;
- private ButtonViewHolder holder;
- private LayoutInflater mInflater;
- private String[] keyString;
- private int[] valueViewID;
- // 构造函数初始化变量
- public MyButtonAdapter(Context context, List<Map<String, Object>> list,
- int resource, String[] from, int[] to) {
- this.mContext = context;
- this.mList = list;
- // 获得布局文件对象
- mInflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- keyString = new String[from.length];
- valueViewID = new int[to.length];
- // 复制数组
- System.arraycopy(from, 0, keyString, 0, from.length);
- System.arraycopy(to, 0, valueViewID, 0, to.length);
- }
- @Override
- public int getCount() {
- return list.size();
- }
- @Override
- public Object getItem(int position) {
- return list.get(position);
- }
- /**
- * 从list中移除某一项
- *
- * @param position
- */
- public void removeItem(int position) {
- list.remove(position);
- // 通知数据集已改变,请求自刷新
- this.notifyDataSetChanged();
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView != null) {
- holder = (ButtonViewHolder) convertView.getTag();
- } else {
- convertView = mInflater.inflate(R.layout.list_item, null);
- holder = new ButtonViewHolder();
- holder.name = (TextView) convertView
- .findViewById(valueViewID[0]);// 岗位名称
- holder.num = (TextView) convertView
- .findViewById(valueViewID[1]);// 岗位数量
- holder.date = (TextView) convertView
- .findViewById(valueViewID[2]);// 发布日期
- holder.description = (TextView) convertView
- .findViewById(valueViewID[3]);// 岗位描述
- holder.btn = (Button) convertView.findViewById(valueViewID[4]);// 报名按钮
- convertView.setTag(holder);
- }
- Map<String, Object> appInfo = mList.get(position);
- if (appInfo != null) {
- String aname = (String) appInfo.get(keyString[0]);
- Integer anum = (Integer) appInfo.get(keyString[1]);
- String adate = (String) appInfo.get(keyString[2]);
- String adescription = (String) appInfo.get(keyString[3]);
- holder.name.setText(aname);
- holder.num.setText(anum + "");
- holder.date.setText(adate);
- holder.description.setText(adescription);
- // 报名按钮事件
- holder.btn.setOnClickListener(new lvButtonListener(position));
- }
- return convertView;
- }
- class lvButtonListener implements OnClickListener {
- private int position;
- lvButtonListener(int pos) {
- position = pos;
- }
- @Override
- public void onClick(View v) {
- int vid = v.getId();
- if (vid == holder.btn.getId()) {
- String result = "" + "岗位名称:"
- + list.get(position).get("name") + "\r\n" + "岗位人数:"
- + list.get(position).get("num") + "\r\n" + "发布日期:"
- + list.get(position).get("date") + "\r\n" + "岗位描述:"
- + list.get(position).get("description") + "\r\n";
- new AlertDialog.Builder(MainActivity.this)
- .setTitle("提示")
- .setIcon(R.drawable.ic_launcher)
- .setMessage(result + "\r\n" + "您确定要申请该岗位吗?")
- .setPositiveButton(R.string.positive,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(
- DialogInterface dialog,
- int which) {
- Toast toast = Toast
- .makeText(
- MainActivity.this,
- "您点击了"
- + getResources()
- .getString(
- R.string.positive)
- + "按钮,申请了"
- + list.get(
- position)
- .get("name")
- + "的岗位!",
- Toast.LENGTH_SHORT);
- toast.setGravity(Gravity.CENTER, 0,
- 0);
- toast.show();
- }
- })
- .setNegativeButton(R.string.negative,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(
- DialogInterface dialog,
- int which) {
- Toast toast = Toast
- .makeText(
- MainActivity.this,
- "您点击了"
- + getResources()
- .getString(
- R.string.negative)
- + "按钮",
- Toast.LENGTH_SHORT);
- toast.setGravity(Gravity.CENTER, 0,
- 0);
- toast.show();
- }
- }).create().show();
- // 如果要删除行,可以调用此方法
- // removeItem(position);
- }
- }
- }
- }
- }
上面的代码有几个知识点需要注意:
1、SQLite数据库的查询操作
我们通过getReadableDatabase().query方法执行了查询操作,返回Cursor(游标,与JDBC中的ResultSet类似)对象。
2、ListView控件使用(重点)
我们参考了SimpleAdapter默认的构造函数的方法,创建了自定义的MyButtonAdapter类,在显示数据的同时,能够给每一行的按钮绑定点击事件。
3、弹出提示框
弹出提示框的代码很长,完全可以封装到一个方法中,简化代码。这里完整的列出来,目的就是体验一下设计思路。经过观察我们发现,这就是所谓的“链式编程”,可以通过连续的".",设置参数(控制显示效果)。
strings.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="positive">确定</string>
- <string name="negative">取消</string>
- </resources>
最终在pad上面的执行效果如下:
Android开发系列之ListView的更多相关文章
- C# WinForm开发系列 - ListBox/ListView/Panel
转自会飞的小猪文章 C# WinForm开发系列 - ListBox/ListView/Panel 在博客园看到了一篇博文,觉得很不错,就转载过来了. 包含自定义绘制的ListBox, 带拖动, ...
- Android 开发系列教程之(一)Android基础知识
什么是Android Android一词最早是出现在法国作家维里耶德利尔·亚当1986年发表的<未来夏娃>这部科幻小说中,作者利尔·亚当将外表像人类的机器起名为Android,这就是And ...
- Android开发之去掉listview的点击效果,一行代码间接粗暴,解决你的问题。
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 Android开发之去掉listview的点击效果,一行代码间接粗暴,解决你的问题. 当你在用list ...
- [Android开发系列]IT博客应用
1.关于坑 好吧,在此之前先来说一下,之前开的坑,恩,确实是坑,前面开的两个android开发教程的坑,对不起,实在是没什么动力了,不过源码都有的,大家可以参照github这个应用 https://g ...
- Android开发系列之按钮事件的4种写法
经过前两篇blog的铺垫,我们今天热身一下,做个简单的例子. 目录结构还是引用上篇blog的截图. 具体实现代码: public class MainActivity extends Activity ...
- Android开发系列之SQLite
上篇博客提到过SQLite,它是嵌入式数据库,由于其轻巧但功能强大,被广泛的用于嵌入式设备当中.后来在智能手机.平板流行之后,它作为文件型数据库,几乎成为了智能设备单机数据库的必选,可以随着安卓app ...
- Android开发系列之Android项目的目录结构
今天开始正式学习Android开发的种种细节,首先从最基本的概念和操作学起. 首先看一下Android项目的目录结构. 这是我随便建立的一个test项目,我们重点关注一下几个方面的内容: 1.src目 ...
- Android开发系列之学习路线图
通过前面的3篇博客已经简单的介绍了Android开发的过程并写了一个简单的demo,了解了Android开发的环境以及一些背景知识. 接下来这篇博客不打算继续学习Android开发的细节,先停一下,明 ...
- Android开发系列之搭建开发环境
接触Android好久了,记得09年刚在中国大陆有点苗头的时候,我就知道了google有个Android,它是智能机操作系统.后来在Android出1.5版本之后,我第一时间下载了eclipse开发工 ...
随机推荐
- Java路径操作具体解释
1.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或文件夹在硬盘上真正的路径.(URL和物理路径)比如: C:\xyz\test.txt 代表了test.txt文件的绝对路径.http://w ...
- MFC——从实现角度分析微云界面
在云计算时代之风吹来,很多互联网公司都在建云,提出云盘.云储存.云平台.云空间等等,骤然间,天下皆云.云是啥?有用户量,就有云,没有用户量,你的系统,你的云,也就是一朵白云. 最近研究了下微云的界面, ...
- android学习日记03--常用控件ListView
常用控件 8.ListView 列表视图,比如游戏的排行榜.列表数据可以根据屏幕大小自适应 列表的显示需要三个元素: a.ListVeiw:用来展示列表的View. b.适配器:用来把数据映射到Lis ...
- (转)如何在JavaScript与ActiveX之间传递数据2
本文研究如何在JS等脚本语言与ActiveX控件之间通信,如何传递各种类型的参数,以及COM的IDispatch接口.使用类似的方法,可以推广到其他所有脚本型语言,如LUA,AutoCad等.本文将研 ...
- careercup-C和C++ 13.6
13.6 基类的析构函数为何要声明为virtual? 解答: 用对象指针来调用一个函数,有以下两种情况: 如果是虚函数,会调用派生类中的版本. 如果是非虚函数,会调用指针所指类型的实现版本. 析构函数 ...
- .net core 1.1.0 MVC 控制器接收Json字串 (JObject对象) (二)
.net core 1.1.0 MVC 控制器接收Json字串 (JObject对象) (二) .net core 1.1.0 MVC 控制器接收Json字串 (JObject对象) (一) 上一篇主 ...
- linux实例 批量修改图片文件名
1.如10.11一批这样的目录,10.11 10.12等等 然后里面的图片.jpg文件要修改成对应的日期.jpg,也就是说 编程1011.jpg这样的文件名 示例如下: #!/bin/bashfor ...
- 【转】 使用Beaglebone Black的PRU(三)——实现高达100MHz的GPIO输出
友情提示:请先按照本系列(一)(二)的说明安装PRU工具并跑通hello world再继续按本文操作. PRU操作GPIO有很多种方式,本系列之(二)中的是一种,但最快速的方式是通过直接“写”r30和 ...
- 关于iOS自定义返回按钮右滑返回手势失效的解决:
在viewDidLoad方法里面添加下面这一句代码即可 self.navigationController.interactivePopGestureRecognizer.delegate=(id)s ...
- (转)fastdfs_v4.07 / 实现多服务器
http://my.oschina.net/shking/blog/165326 自己闲着没事,在小黑上虚拟了 4 个 centos 64 的系统,用来安装分布式 fastdfs . nginx 负载 ...