除了基于监听的的事件处理模型外,安卓还提供了一种事件处理模型:基于回调的事件处理模型
为了使用回调机制类处理UI组件上发生的事件,我们需要为该组件提供对应的事件处理方法,但是Java又是静态语言,我们不能动态的为某一个对象添加方法,所以我们只能继承UI组件类,并重写该类的事件处理方法来实现,这就是基于回调的事件处理机制。
为了实现回调机制的事件处理,安卓为几乎所有的UI组件都提供了一些事件处理的回调方法,已View为例,该类中含有如下回调方法:
》boolean onKeyDown(int KeyCode,KeyEvent event)
》boolean onKeyUp(int KeyCode,KeyEvent event)
》boolean onTouchEvent(MotionEvent event)
》boolean onKeyLongPressed(int KeyCode,KeyEvent event)
》boolean onTrackballEvent(MotionEvent event)
》boolean onKeyShortcut(int KeyCode,KeyEvent event)
我们通过代码来理解基于回调的机制:
public MyButton extends Button{
public MyButton(Context context,AttributeSet set){
super(context,set);
}
@Override
public boolean onKeyDown(int keyCode,KeyEvent event){
super.onKeyDown(keyCode,event);
Log.v("youlebron","the button is clicked");
return true;
}
}
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.youlebon.event.MyButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="test"
/>
</LinearLyaout>
首先我们定义了已继承了Button类的MyButton类,重写里面有关事件处理的回调方法,然后我们在布局界面的xml文件中使用这个MyButton类,这样当点击按钮时,
会实现事件处理。
几乎所有的基于回调的事件处理方法都有一个boolean类型的返回值,该返回值返回值用于标识该处理方法能否完全处理该事件。
除了上面两种事件处理机制外,安卓还提供了一种消息处理机制,其目的是解决安卓应用的多线程问题,由于安卓不允许Activity新启动的线程不能访问该Activit中的界面组件,这样就导致新启动的线程不能动态改变界面组件的函数属性值。这样就需要借助于Handle的消息传递机制来实现。
Handle类的主要作用有两个:
》在新启动的线程中发送信息
》在主线程中获取,处理信息
Handle类包含如下的方法用于发送与处理信息:
》void handleMessage(Message msg)
》final boolean hasMessage(int what)
》final boolean sendMessage(Message msg)
》final boolean sendMessageDelayed(Message msg,long delayMillis)
下面通过简单地C—S聊天应用例子说明Handle类的作用;
public class ClientThread implements Runnable
{
//该线程负责处理的Socket
private Socket s;
private Handler handler;
//该线程所处理的Socket所对应的输入流
BufferedReader br = null;
public ClientThread(Socket s , Handler handler)
throws IOException
{
this.s = s;
this.handler = handler;
br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
}
public void run()
{
try
{
String content = null;
//不断读取Socket输入流中的内容。
while ((content = br.readLine()) != null)
{
// 每当读到来自服务器的数据之后,发送消息通知程序界面显示该数据
Message msg = new Message();
msg.what = 0x123;
msg.obj = content;
handler.sendMessage(msg);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
这个类用于从服务器读取消息的内容,但是由于要新建一个线程,那么如何将读取的消息内容显示在文本框内呢?
这就需要使用Handle类了,在CLientThead中,我们定义了一个handle类,设置what变量为0x123,设置obj变量为读取的内容,然后发送消息,
接着我们编写主Activity类,在其中我们再定义一个Handle类用来接收新线程中定义的Handle类发送的消息,再将它显示在文本框中,这样就解决了新线程不能访问UI组件的问题。
public class MultiThreadClient extends Activity
{
// 定义界面上的两个文本框
EditText input, show;
// 定义界面上的一个按钮
Button send;
OutputStream os;
Handler handler;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
input = (EditText) findViewById(R.id.input);
send = (Button) findViewById(R.id.send);
show = (EditText) findViewById(R.id.show);
Socket s;
handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// 如果消息来自于子线程
if (msg.what == 0x123)
{
// 将读取的内容追加显示在文本框中
show.append("\n" + msg.obj.toString());
}
}
};
try
{
s = new Socket("192.168.1.102", 29999);
// 客户端启动ClientThread线程不断读取来自服务器的数据
new Thread(new ClientThread(s, handler)).start(); // ①
os = s.getOutputStream();
}
catch (Exception e)
{
e.printStackTrace();
}
send.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
try
{
// 将用户在文本框内输入的内容写入网络
os.write((input.getText().toString() + "\r\n")
.getBytes("utf-8"));
// 清空input文本框
input.setText("");
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
}
所以,安卓主要的事件处理模型就是这三种了:基于监听器的事件处理模型,基于回调方式的事件处理模型,Handle消息传递模型。