五一放了个假,休息了几天、、、、
这次主要是运用数据库,Android内嵌有SQLite,这是一款轻量级的数据库,具体的可以百度。效果呢,主要是通过一些点击事件实现数据的插入,查找,修改,删除,最后通过一个listview表现出来。效果如下(因为是动态的,图示仅供参考,可以下载放在最后的源码自己跑跑看)
关于实现的功能如下:1、完成3个填选框后后,点击提交可以插入数据。并自动刷新listview,所有数据均由数据库提供。2、点击列表项,弹出对话框,可以选择删除,会从数据库中删除。可以选择修改,此时按钮自动文字编程修正,修改完成后数据会更新。
关于此篇中出现的关于ListView的用法,不多做解释,参考上一篇
鱼鱼Chen之学写自己的apk(六)ListView带动画图标
http://blog.csdn.net/zerolovesc1993/article/details/45334699
同理,关于Handler Message的用法,参考
鱼鱼Chen之学写自己的apk(五)使用Handler完成Android里的多线程操作实例
http://blog.csdn.net/zerolovesc1993/article/details/45270153
下面正式开始:
一、分析一下结构
ListViewItem是我自定义的列表项类,MyListViewAdapter是我自定义的listview适配器。MySqliteHelper是自定义的sqlite生成器。布局的话,老样子,分别对应主布局和listview的布局
二、先配置好listview
布局文件xml,很简单,3个textview,稍微拍一下版就好了
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/list_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:textSize="30sp" />
<TextView
android:id="@+id/list_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/list_name"
android:layout_marginTop="16dp"
android:textSize="20sp" />
<TextView
android:id="@+id/list_class"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="20dp"
android:textSize="25sp" />
</RelativeLayout>
接着,是listviewadapter的代码,这些就不解释了,参考之前的就好。直接上代码
package com.dota.example.fishychenofsqlite;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class MyListViewAdapter extends ArrayAdapter<ListViewItem> {
private Context context;
private int resourceId;
private ListViewItem item;
private ViewHolder holder;
public MyListViewAdapter(Context context, int resource,
List<ListViewItem> objects) {
super(context, resource, objects);
this.context = context;
this.resourceId = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
item = getItem(position);
if (convertView == null) {
view = LayoutInflater.from(context).inflate(resourceId, parent,
false);
holder = new ViewHolder();
holder.textName = (TextView) view.findViewById(R.id.list_name);
holder.textNumber = (TextView) view.findViewById(R.id.list_number);
holder.textClass = (TextView) view.findViewById(R.id.list_class);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
holder.textName.setText(item.getName());
holder.textClass.setText(item.getClasses());
holder.textNumber.setText(item.getNumber());
return view;
}
}
class ViewHolder {
TextView textName, textNumber, textClass;
}
接着是自定义的listview的item项
public class ListViewItem {
private String name, classes, number;
public ListViewItem(String name, String classes, String number) {
this.name = name;
this.classes = classes;
this.number = number;
}
public String getName() {
return name;
}
public String getClasses() {
return classes;
}
public String getNumber() {
return number;
}
}
三、创建自定义的sqlite打开帮助器
还是先上代码,再做解释
public class MySqliteHelper extends SQLiteOpenHelper {
private Context context;
private static final String CREATE_TABLE = "create table MyTable("
+ "id integer primary key autoincrement, " + "name text unique, "
+ "class text, " + "number text)";
public MySqliteHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
首先我们让自定义类继承SQLiteOpenHelper,实现2个抽象方法。并实现构造方法,4个参数,分别代表上下文、名称(db格式)、指针工厂(null就行,指向数据库某一行,一般用不到)、版本号
结合着主活动中的实例化,我们看一下用法
dbHelper = new MySqliteHelper(this, "Table.db", null, 1);
当Table.db不存在时,便会调用onCreate中的代码,存在便无影响。除非version的int比之前大,比如是2。那么此时会调用onUpgrade方法。db.execSQL即可生成某个表格
关于创建表格的格式几个注意点:栏名 格式 约束条件(可选),其中格式有integer(整形),text(文本),real(浮点型),blob(数据块)。 primary key指唯一键,autoincrement指自增长。而unique关键字指唯一,即不能重复插入无效。还有一个要注意的是,输入某一栏后记得加空格,新手容易犯这个错误,否则会报错,因为你输入的sql语句是有问题的。
关于创建,主要在主活动中oncreate方法里写入,就可以了
dbHelper = new MySqliteHelper(this, "Table.db", null, 1);
private void initData() {
items.clear();
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("MyTable", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex("name"));
String classes = cursor.getString(cursor
.getColumnIndex("class"));
String number = cursor.getString(cursor
.getColumnIndex("number"));
items.add(new ListViewItem(name, classes, number));
} while (cursor.moveToNext());
}
}
先通过我们自定义的类的实力对象,使用getWriteableDatabase方法,得到sqlitedatabase实例对象。(其实这边用getReadableDatabase可能会更好,该方法会调用getWriteableDatabase)。然后用Cursor类的实例对象实现db.query方法。7个参数,第一个是表格名,第二个是栏名,第三个和第四个连起来是一个完整的约束条件。比如
"name = ?"(第三个), new String[] { editName.getText().toString() }(第四个)。后三个一般用不到,也是3个约束条件,具体用法可以百度sqlite语法。这边我只要表内的所有数据。记得,一定要加
if (cursor.moveToFirst())
这个判断,不然会报错。表明cursor能指向第一项。循环内的还是比较好理解的,通过的cursor的getxxx方法(xxx代表数据类型),然后得到对应的栏名。最后将其加入自定义的列表项集合里。
这边,要用到多线程操作。因为遍历数据库,以及配置适配器都算是耗时操作。
class NewThread extends Thread implements Runnable {
@Override
public void run() {
super.run();
synchronized (MainActivity.class) {
try {
initData();
itemAdapter = new MyListViewAdapter(MainActivity.this,
R.layout.listview_layout, items);
Message message = new Message();
message.what = UPDATA_LISTVIEW;
mHandler.sendMessage(message);
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
handler中的代码
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case UPDATA_LISTVIEW:
listView.setAdapter(itemAdapter);
break;
default:
break;
}
}
};
这次为了方便,我直接用了匿名类。
定义
private static final int UPDATA_LISTVIEW = 1;
事件我是写在按钮里的
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", editName.getText().toString());
values.put("class", spinner.getSelectedItem().toString());
values.put("number", editNumber.getText().toString());
try {
db.insert("MyTable", null, values);
Toast.makeText(MainActivity.this, "插入成功", Toast.LENGTH_SHORT)
.show();
mThread = new NewThread();
mThread.start();
} catch (Exception e) {
// TODO: handle exception
}
第一步是一样的,得到db这个实例对象。并创建一个ContentValues类的实例对象。通过put方法,填入值,记得key对应栏名。最后调用insert方法就行了,这边3个参数,分别是表名、
nullColumnHack、值。第二个参数是干啥的呢?
当values参数为空或者里面没有内容的时候,我们insert是会失败的(底层数据库不允许插入一个空行),为了防止这种情况,我们要在这里指定一个 列名,到时候如果发现将要插入的行为空行时,就会将你指定的这个列名的值设为null,然后再向数据库中插入。当然了,这边我们直接用null就行,因为我们value的值是不可能为空的(第二个数据我用的spinner)。实际过程中,填入数据的时候,加一个适当的判断就可以了。
五、实现数据的更新
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", editName.getText().toString());
values.put("class", spinner.getSelectedItem().toString());
values.put("number", editNumber.getText().toString());
db.update("MyTable", values, "name = ?", new String[] { editName
.getText().toString() });
这边和插入差不多,只不过updata是4个参数,分别是表名、值、约束条件(2个参数),这种写法之前在查找部分已经说过了。
六、实现数据的删除
SQLiteDatabase db = dbHelper
.getWritableDatabase();
db.delete("MyTable", "name = ?",
new String[] { items.get(position)
.getName() });
这边的话,和更新的格式是差不多的,delete方法是3个参数,表名、约束条件组。
接下来是完整的主活动的代码
public class MainActivity extends Activity implements OnFocusChangeListener,
OnClickListener {
private EditText editName, editNumber;
private Spinner spinner;
private ListView listView;
private List<ListViewItem> items;
private ArrayAdapter<CharSequence> adapter;
private MyListViewAdapter itemAdapter;
private Button btnSubmit;
private MySqliteHelper dbHelper;
public Handler mHandler;
private Thread mThread;
private boolean flag = true;
private static final int UPDATA_LISTVIEW = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case UPDATA_LISTVIEW:
listView.setAdapter(itemAdapter);
break;
default:
break;
}
}
};
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
final int position, long id) {
AlertDialog.Builder dialog = new AlertDialog.Builder(
MainActivity.this);
dialog.setTitle("核对");
dialog.setMessage("确定要删除吗?");
dialog.setPositiveButton("确认",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
SQLiteDatabase db = dbHelper
.getWritableDatabase();
db.delete("MyTable", "name = ?",
new String[] { items.get(position)
.getName() });
items.remove(position);
mThread = new NewThread();
mThread.start();
}
});
dialog.setNegativeButton("修正",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
editName.setText(items.get(position).getName());
editNumber.setText(items.get(position)
.getNumber());
flag = false;
btnSubmit.setText("修正");
}
});
dialog.show();
}
});
mThread = new NewThread();
mThread.start();
}
private void init() {
CharSequence[] charSequences = getResources().getStringArray(
R.array.spinner_item_name);
adapter = new ArrayAdapter<CharSequence>(this,
android.R.layout.simple_spinner_item, charSequences);
dbHelper = new MySqliteHelper(this, "Table.db", null, 1);
editName = (EditText) findViewById(R.id.editName);
editNumber = (EditText) findViewById(R.id.editNumber);
spinner = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);
listView = (ListView) findViewById(R.id.listView);
items = new ArrayList<ListViewItem>();
btnSubmit = (Button) findViewById(R.id.btnSubmit);
editName.setOnFocusChangeListener(this);
editNumber.setOnFocusChangeListener(this);
btnSubmit.setOnClickListener(this);
initData();
}
private void initData() {
items.clear();
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("MyTable", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex("name"));
String classes = cursor.getString(cursor
.getColumnIndex("class"));
String number = cursor.getString(cursor
.getColumnIndex("number"));
items.add(new ListViewItem(name, classes, number));
} while (cursor.moveToNext());
}
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
((EditText) v).setHint("");
switch (v.getId()) {
case R.id.editName:
if ((editName.getText().toString().equals("")) && !hasFocus) {
editName.setHint("请输入姓名");
}
break;
case R.id.editNumber:
if ((editNumber.getText().toString().equals("")) && !hasFocus) {
editNumber.setHint("请输入学号");
}
break;
default:
break;
}
}
@Override
public void onClick(View v) {
if (flag) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", editName.getText().toString());
values.put("class", spinner.getSelectedItem().toString());
values.put("number", editNumber.getText().toString());
try {
db.insert("MyTable", null, values);
Toast.makeText(MainActivity.this, "插入成功", Toast.LENGTH_SHORT)
.show();
mThread = new NewThread();
mThread.start();
} catch (Exception e) {
// TODO: handle exception
}
} else {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", editName.getText().toString());
values.put("class", spinner.getSelectedItem().toString());
values.put("number", editNumber.getText().toString());
db.update("MyTable", values, "name = ?", new String[] { editName
.getText().toString() });
btnSubmit.setText("提交");
flag = true;
mThread = new NewThread();
mThread.start();
}
}
class NewThread extends Thread implements Runnable {
@Override
public void run() {
super.run();
synchronized (MainActivity.class) {
try {
initData();
itemAdapter = new MyListViewAdapter(MainActivity.this,
R.layout.listview_layout, items);
Message message = new Message();
message.what = UPDATA_LISTVIEW;
mHandler.sendMessage(message);
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
}
主布局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:focusable="true"
android:focusableInTouchMode="true"
tools:context="com.dota.example.fishychenofsqlite.MainActivity" >
<RelativeLayout
android:id="@+id/relativeLayoutTop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:padding="8dp" >
<TextView
android:id="@+id/textName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名"
android:textSize="25sp" />
<EditText
android:id="@+id/editName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/textName"
android:hint="请输入姓名"
android:lines="1"
android:maxLines="1" />
<TextView
android:id="@+id/textClass"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textName"
android:layout_marginTop="16dp"
android:text="班级"
android:textSize="25sp" />
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/textClass"
android:layout_below="@+id/editName"
android:layout_toRightOf="@+id/textClass" />
<TextView
android:id="@+id/textNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textClass"
android:layout_marginTop="16dp"
android:text="学号"
android:textSize="25sp" />
<EditText
android:id="@+id/editNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/textNumber"
android:layout_toRightOf="@+id/textNumber"
android:hint="请输入学号"
android:inputType="number" />
<Button
android:id="@+id/btnSubmit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/editNumber"
android:text="提交"
android:textSize="20sp" />
</RelativeLayout>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/relativeLayoutTop" >
</ListView>
</RelativeLayout>
最后是完整的代码
百度云链接:http://pan.baidu.com/s/1pJKDUkF