上篇博客解决了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布局文件:
可以看到这是一个相对布局,里面有一个线性布局,线性布局里面又放置了4个TextView作为ListView数据的标题。下面直接是一个ListView控件,由于这是相对布局,为了让ListView显示在“表头”下面,我们设置了layout_below属性。此外要注意ListView的id的写法。
接着按照界面的要求,我们准备一下ListView加载布局文件的内容,我们起名为:list_item.xml。
list_item.xml:
这也是一个普通的线性布局,设置orientation为horizontal(水平)。
布局文件准备好,下面我们准备写代码了。
我们让MainActivity这个类继承自ListActivity,完整的代码如下:
public class MainActivity extends ListActivity {
List> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = new ArrayList>();
//初始化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>数据结构当中
while (cursor.moveToNext()) {
Map map = new HashMap();
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 map = (HashMap) 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> mList;
private ButtonViewHolder holder;
private LayoutInflater mInflater;
private String[] keyString;
private int[] valueViewID;
// 构造函数初始化变量
public MyButtonAdapter(Context context, List> 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 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:
确定
取消
最终在pad上面的执行效果如下: