Android控件开发——ListView

简介: 上篇博客解决了Android客户端通过WebService与服务器端程序进行交互的问题,这篇博客重点关注两个问题,一个是Android应用程序如何与本机文件型数据库SQLite进行交互,另一问题则是如何在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上面的执行效果如下:





目录
相关文章
|
14小时前
|
安全 Linux Android开发
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
该文介绍了如何在Linux服务器上交叉编译Android的FFmpeg库以支持HTTPS视频播放。首先,从GitHub下载openssl源码,解压后通过编译脚本`build_openssl.sh`生成64位静态库。接着,更新环境变量加载openssl,并编辑FFmpeg配置脚本`config_ffmpeg_openssl.sh`启用openssl支持。然后,编译安装FFmpeg。最后,将编译好的库文件导入App工程的相应目录,修改视频链接为HTTPS,App即可播放HTTPS在线视频。
14 3
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
|
2天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。
|
5天前
|
存储 Java Android开发
安卓应用开发中的内存优化策略
【4月更文挑战第30天】在移动开发领域,尤其是安卓平台上,内存管理是影响应用性能和用户体验的关键因素。由于安卓设备的硬件资源有限,不合理的内存使用会导致应用响应缓慢、消耗过多电量甚至崩溃。本文将探讨针对安卓平台的内存优化技巧,旨在帮助开发者提高应用的性能和稳定性,从而提升用户满意度。我们将详细讨论内存泄漏的预防、合理的内存分配策略以及高效的内存回收方法。
|
5天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
6天前
|
机器学习/深度学习 安全 数据处理
构建未来:基于Android的智能家居控制系统开发
【4月更文挑战第29天】 随着物联网技术的蓬勃发展,智能家居已成为现代技术革新的重要领域。本文将深入探讨基于Android平台的智能家居控制系统的设计和实现,旨在提供一种用户友好、高度集成且功能丰富的解决方案。通过利用Android设备的广泛普及和其强大的处理能力,结合最新的无线通讯技术和人工智能算法,我们旨在打造一个可靠、易用且具有高度可定制性的智能家居控制环境。文中不仅详细阐述了系统架构、关键技术选型以及界面设计,还对可能遇到的安全挑战进行了分析,并提出了相应的解决策略。
|
6天前
|
监控 Java Android开发
安卓应用开发中的内存优化策略
【4月更文挑战第29天】在面对安卓设备多样化的硬件配置时,合理管理应用内存成为提升用户体验的关键。本文深入探讨了安卓应用开发中常见的内存泄漏问题,并提出了一系列针对性的优化策略。通过分析内存分配机制、垃圾回收原理及内存监控工具的使用,揭示了高效内存管理的实践方法。文章旨在为开发者提供一套系统的内存优化解决方案,以实现更流畅、稳定的应用性能。
|
6天前
|
监控 Java Android开发
安卓应用开发:打造高效用户界面的五大策略
【4月更文挑战第29天】 在安卓应用开发的世界中,构建一个既美观又高效的用户界面(UI)对于吸引和保留用户至关重要。本文将深入探讨五种策略,这些策略可以帮助开发者优化安卓应用的UI性能。我们将从布局优化讲起,逐步过渡到绘制优化、内存管理、异步处理以及最终的用户交互细节调整。通过这些实践技巧,你将能够为用户提供流畅而直观的体验,确保你的应用在竞争激烈的市场中脱颖而出。
|
6天前
|
编解码 测试技术 Android开发
安卓应用开发:打造流畅的用户体验
【4月更文挑战第29天】在竞争激烈的应用市场中,一个具有流畅用户体验的安卓应用是吸引和保留用户的关键因素。本文将深入探讨如何通过优化代码、使用高效的架构模式以及利用安卓系统提供的工具来提升应用性能,从而打造出让用户满意的流畅体验。
|
8天前
|
机器学习/深度学习 搜索推荐 Android开发
【专栏】安卓应用开发:构建高效用户界面的实用指南
【4月更文挑战第27天】本文介绍了构建高效安卓用户界面的指南,分为设计原则和技巧两部分。设计原则包括一致性、简洁性和可访问性,强调遵循安卓系统规范,保持界面简洁,考虑不同用户需求。技巧方面,建议合理布局、优化图标和图片、运用动画效果、提供个性化设置及优化性能。随着技术发展,未来安卓应用开发将融合更多智能化和个性化元素,开发者需持续学习新技术,提升用户体验。
|
11天前
|
数据库 Android开发 开发者
安卓应用开发:构建高效用户界面的策略
【4月更文挑战第24天】 在竞争激烈的移动应用市场中,一个流畅且响应迅速的用户界面(UI)是吸引和保留用户的关键。针对安卓平台,开发者面临着多样化的设备和系统版本,这增加了构建高效UI的复杂性。本文将深入分析安卓平台上构建高效用户界面的最佳实践,包括布局优化、资源管理和绘制性能的考量,旨在为开发者提供实用的技术指南,帮助他们创建更流畅的用户体验。