Android Handler与数据库的实现方法 (android handler 数据库)

在Android开发中,数据库操作和UI更新是非常常见的需求,如何在不阻塞UI线程的情况下进行数据库操作,然后将结果更新到UI上,成为了一项重要的技术挑战。Android Handler便是解决这一问题的重要工具。本文将从概念介绍、实现方法和实际应用三个角度来详细说明。

一、概念介绍

Handler是Android中的一个重要类,它是Android消息机制的基础。通俗地讲,Handler就是一个消息循环,专门用来处理Message对象的。在实践中,我们通过Handler可以实现线程之间消息的发送与处理,从而完成异步处理任务和UI更新。

数据库操作是Android开发中非常重要的一环。它可以持久保存App数据并支持数据的增删改查等基本操作,SQLite是Android中默认的数据库。但在进行数据库操作时,我们需要注意,所有的I/O操作都是在UI线程中进行的,如果数据操作任务比较复杂,程序就会阻塞UI线程,造成程序响应缓慢,严重的话,程序会崩溃。

最早的解决方法是采用线程的方式,将数据库操作放在子线程中进行,然后通过Handler来将处理结果推回UI线程中。这一方法的好处是可以防止ANR(应用未响应)情况的出现,但也存在一些问题。比如,多个操作需要在同一个子线程中被执行,此时就需要一个另外的机制来处理消息循环。

二、实现方法

通过Handler来进行数据库操作和UI更新,需要我们掌握以下的实现方法。

1.在Activity中定义Handler

“`

class UIHandler extends Handler {

public static final int

MSG_QUERY_SUCCESS=0x001,

MSG_QUERY_ERROR=0x002,

MSG_INSERT_SUCCESS=0x101,

MSG_INSERT_ERROR=0x102;

private WeakReference mActivity;

UIHandler(MnActivity activity){

mActivity=new WeakReference(activity);

}

@Override

public void handleMessage(Message msg) {

MnActivity activity=mActivity.get();

switch (msg.what) {

case MSG_QUERY_SUCCESS:{

List students=(List)msg.obj;

activity.updateUI(students);

} break;

case MSG_QUERY_ERROR:{

activity.showToast(“查询失败”);

} break;

case MSG_INSERT_SUCCESS:{

int id=msg.arg1;

activity.editId=id;

activity.showToast(“添加成功”);

} break;

case MSG_INSERT_ERROR:{

activity.showToast(“添加失败”);

} break;

}

}

}

“`

此处我们定义了一个UIHandler类,它继承自Handler,采用了内部类的形式被MnActivity引用。它实现了handleMessage方法,用于处理不同的消息类型,并将消息的结果传递到MnActivity中更新UI。

在上述例子中,我们定了了4种不同的消息类型(分别表示查询成功、查询失败、添加成功和添加失败),每个消息都有其自己的处理方式。通过Message的传递,我们可以实现在子线程中进行消息的传递,从而达到异步处理任务的目的。

在UIHandler的构造函数中,我们通过WeakReference对MnActivity进行了引用,这是为了避免对Activity对象的持有,使Activity可以自动被回收从而降低内存泄露的风险。

2.在子线程中执行数据库操作

在子线程中执行数据库操作时,我们通常采用Runnable或者Thread来实现,此处以Runnable为例。

“`

class DatabaseTask implements Runnable {

private Handler mHandler;

private String mName;

public DatabaseTask(Handler handler, String name){

mHandler=handler;

mName=name;

}

@Override

public void run(){

List students=new ArrayList();

//开启数据库操作

SQLiteDatabase db=…;

try{

Cursor cursor=db.rawQuery(“select * from student”, null);

while(cursor.moveToNext()){

int id=cursor.getInt(cursor.getColumnIndex(“id”));

String name=cursor.getString(cursor.getColumnIndex(“name”));

int age=cursor.getInt(cursor.getColumnIndex(“age”));

students.add(new Student(id, name, age));

}

//数据操作成功,发送消息

mHandler.obtnMessage(UIHandler.MSG_QUERY_SUCCESS, students).sendToTarget();

} catch(Exception e){

//数据操作失败,发送消息

mHandler.obtnMessage(UIHandler.MSG_QUERY_ERROR).sendToTarget();

}

}

}

“`

在该线程中,我们封装了一段获取Student数据的操作,它通过Cursor对象遍历数据库,然后将查询到的所有Student封装在一个列表中,并通过Handler发送到UI线程中。如果操作成功,则发送UIHandler中的MSG_QUERY_SUCCESS消息,否则发送MSG_QUERY_ERROR消息。sendMessage不能直接在子线程中被调用,需要使用Handler的obtnMessage方法来将消息打包推送到消息循环中。

3.在Activity中绑定子线程

通过上述第1步和第2步,我们已经分别定义了Handler和子线程,但这两个是密不可分的。我们需要将Handler传到子线程中,并将子线程绑定在Activity中,实现子线程与UI线程之间的通信。

“`

class MnActivity extends AppCompatActivity {

private UIHandler mHandler;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_mn);

mHandler=new UIHandler(this);

}

public void onClickQuery(View view){

//查询–开启子线程

DatabaseTask task=new DatabaseTask(mHandler, “query”);

new Thread(task).start();

}

}

“`

在上述例子中,我们通过new操作符创建了一个DatabaseTask对象,并将Handler作为其参数传入。然后,我们通过Thread的启动方式来启动子线程执行查询操作。

4.更新UI

将查询结果更新到UI中需要手动实现,此处以ListView为例。假设我们已经获取到查询结果的students,那么更新UI的代码如下:

“`

public void updateUI(List students) {

mListAdapter.clear();

mListAdapter.addAll(students);

mListAdapter.notifyDataSetChanged();

}

“`

此处的mListAdapter为一个ArrayAdapter类型,用于ListView的数据绑定。

三、实际应用

在实际应用中,Android Handler与数据库的结合特别常见。以下是一个完整的例子,通过Handler实现异步地向数据库中添加一条学生信息,并将结果显示在UI上。

1.定义Activity中的UIHandler

“`

class UIHandler extends Handler {

public static final int

MSG_INSERT_SUCCESS=0x1,

MSG_INSERT_ERROR=0x2;

private WeakReference mActivity;

UIHandler(MnActivity activity){

mActivity=new WeakReference(activity);

}

@Override

public void handleMessage(Message msg) {

MnActivity activity=mActivity.get();

switch (msg.what) {

case MSG_INSERT_SUCCESS:{

int id=msg.arg1;

activity.showToast(“添加成功”);

activity.editId=id;

} break;

case MSG_INSERT_ERROR:{

activity.showToast(“添加失败”);

} break;

}

}

}

“`

2. 定义添加操作的子线程

“`

class InsertTask implements Runnable {

private Handler mHandler;

private String mName;

private int mAge;

public InsertTask(Handler handler, String name, int age){

mHandler=handler;

mName=name;

mAge=age;

}

@Override

public void run(){

int result=-1;

//开启数据库操作

SQLiteDatabase db=…;

try{

ContentValues values=new ContentValues();

values.put(“name”, mName);

values.put(“age”, mAge);

result=(int)db.insert(“student”, null, values);

//数据操作成功,发送消息

mHandler.obtnMessage(UIHandler.MSG_INSERT_SUCCESS, result, -1).sendToTarget();

} catch(Exception e){

//数据操作失败,发送消息

mHandler.obtnMessage(UIHandler.MSG_INSERT_ERROR).sendToTarget();

}

}

}

“`

3. 完整的Activity代码

“`

public class MnActivity extends AppCompatActivity {

private UIHandler mHandler;

private EditText mNameEditText;

private EditText mAgeEditText;

private ListView mListView;

private ArrayAdapter mListAdapter;

private int editId=-1;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_mn);

mHandler=new UIHandler(this);

mNameEditText=findViewById(R.id.edit_text_name);

mAgeEditText=findViewById(R.id.edit_text_age);

mListView=findViewById(R.id.list_view_students);

mListAdapter=new ArrayAdapter(this, android.R.layout.simple_list_item_1);

mListView.setAdapter(mListAdapter);

}

public void onClickInsert(View view){

String name=mNameEditText.getText().toString().trim();

int age=Integer.parseInt(mAgeEditText.getText().toString().trim());

if(name.length()==0||age==0) return;

if(editId==-1){

InsertTask task=new InsertTask(mHandler, name, age);

new Thread(task).start();

} else {

// TODO: Update student record.

}

}

public void showToast(String message){

Toast.makeText(this, message, Toast.LENGTH_SHORT).show();

}

public void updateUI(List students) {

mListAdapter.clear();

mListAdapter.addAll(students);

mListAdapter.notifyDataSetChanged();

}

}

“`

在 onClickInsert 方法中,首先获取到名字和年龄的值,然后判断是否为空。如果为空,则直接返回;如果不为空,则启动InsertTask来添加一条Student记录。需要注意的是,如果editId变量的值不是-1,则说明需要更新学生记录的信息,由于篇幅限制,这里不再赘述。

四、


数据运维技术 » Android Handler与数据库的实现方法 (android handler 数据库)