在开发安卓应用的过程中,我们会碰到很多耗时长的过程,例如访问网络,访问数据库等等,通常做法是把它们放到新线程中执行,执行完毕后利用Handler发送消息到主线程,从而修改界面元素或者进行下一步逻辑。
例如,一般的新线程是这样做的
protected class ThreadSaveWeeks extends Thread
{
public void run()
{
//todo:在这里完成耗时长的工作
if (m_handler != null)
{
Message msg = m_handler.obtainMessage();
msg.what = HANDLE_SAVE_COMPLETE;
msg.sendToTarget();
}
}
}
然后在主线程中,需要这样处理
m_handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
if (msg.what == HANDLE_SAVE_COMPLETE)
{
//todo:在这里做相应的界面变化
}
else if (msg.what == HANDLE_LOAD_COMPLETE)
{
//todo:在这里做相应的界面变化
}
}
};
当然,你还需要定义一些常量,用来标注消息编号,例如
static public final int HANDLE_SAVE_COMPLETE = 1;
static public final int HANDLE_LOAD_COMPLETE = 2;
//后面还会有很多...
以上说的只是Handler的最初级使用方法,也是能在网上找到的最普遍的一种。在我最近的工作中,碰到这样的需求:
- 我的安卓应用有多个Activity,每个Activity有多种消息需要处理,其中有私有的,也有公用的。
- 对于公用的消息,绝大多数Activity处理方式相同,少量的Activity有不同的处理要求。
- 对于各个Activity私有的消息,希望他们的msg.what尽量能不重复
总的来说,就是各个Activity和各个消息类型之间的多对多处理,用上面介绍的方法来实现,比较繁琐,很容易出错,也不易修改。所以我对以上的方法进行了一些封装。
首先,我们定义一个接口MessageHandler:
public interface MessageHandler
{
public void handleMessage(Message msg);
}
然后定义一个封装类MessageDealer,其主要成员变量有一个Handler,一个int列表,一个MessageHandler列表
public class MessageDealer
{
Handler m_handler;
ArrayList<Integer> m_eventidlist;
ArrayList<MessageHandler> m_handlerlist;
}
以下是该封装类的构造函数:
public MessageDealer()
{
m_eventidlist = new ArrayList<Integer>();
m_handlerlist = new ArrayList<MessageHandler>();
m_handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
int what = msg.what;
int index = m_eventidlist.indexOf(what);
if (index >= 0)
{
MessageHandler m = m_handlerlist.get(index);
m.handleMessage(msg);
}
else
{
Log.d("MessageDealer","该消息类型尚未被注册");
}
}
};
}
可以看出,这个封装的思路是将待处理的消息类型和处理方法用列表的形式管理起来,当消息被发送到成员m_handler时,在列表中查找消息的类型,再来查找对应的处理方法。
以下是该类的消息注册方法和注销方法:
public boolean RegMessage(int id,MessageHandler method)
{
int inqueue = m_eventidlist.indexOf(id);
if (inqueue < 0)
{
m_eventidlist.add(id);
m_handlerlist.add(method);
return true;
}
else
{
Log.d("MessageDealer","该消息类型已经被注册过了");
return false;
}
}
public boolean UnRegEvent(int id)
{
int inqueue = m_eventidlist.indexOf(id);
if (inqueue < 0)
{
Log.d("MessageDealer","该消息类型未曾注册,也不用注销");
return false;
}
else
{
m_eventidlist.remove(inqueue);
m_handlerlist.remove(inqueue);
Log.d("MessageDealer","该消息类型注销成功");
return true;
}
}
以下是获得Message实例的方法
public Message obtainMessage()
{
if (m_handler != null)
return m_handler.obtainMessage();
else
return null;
}
在实际使用时,可以这样做,先声明一个Activity基类BaseActivity
public class BaseActivity extends Activity
{
MessageDealer m_handler = new MessageDealer();
@Override
public void onResume()
{
super.onResume();
//假设所有activity都需要处理事件1和事件2
m_handler.RegMessage(1, new MessageHandler(){
@Override
public void handleMessage(Message msg) {
Log.d("MessageDealer", "base1");
}});
m_handler.RegMessage(2, new MessageHandler(){
@Override
public void handleMessage(Message msg) {
Log.d("MessageDealer", "base2");
}});
}
}
然后程序的某个activity如下编写
public class MainActivity extends BaseActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onResume()
{
super.onResume();
//假设MainActivity需要对事件1,2,3做出处理
m_handler.RegMessage(3, new MessageHandler(){
@Override
public void handleMessage(Message msg) {
Log.d("MessageDealer", "derive3");
}});
}
}
在MainActivity里发送事件1时,可以这样做
Message msg = m_handler.obtainMessage();
msg.what = 1;
msg.sendToTarget();
可以看到和之前的代码流程并无不同,而灵活性好了很多
项目地址
https://code.csdn.net/maybesong/messagedealerdemo
git地址
git@code.csdn.net:maybesong/messagedealerdemo.git