0.背景
网上关于安卓线程间通讯的文章多如牛毛,以子线程和UI线程为例,我所看到的所有文章都是使用Handler进行通讯,这种方法是非常好的,但是不能应对所有的情况。
问题是这样的,如果我写了一个MainActivity.java,但是我的子线程没有写在这个文件里,而是单独写到了SendThread.java中。那么,在这种情况下二者没有办法共用同一个mHandler,就造成了网上其他文章的方法不适用的情况。
1.View点击事件的相关源码
在阅读相关源码前,先看一下一个很简单的按钮点击事件的实现:
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//TODO:do something
}
});
这里面涉及到两段,一个是setOnClickListener(OnClickListener l),一个是View中的OnClickListener()。代码如下:
/**
* Register a callback to be invoked when this view is clicked. If this view is not
* clickable, it becomes clickable.
*
* @param l The callback that will run
*
* @see #setClickable(boolean)
*/
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
/**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
这两段代码都写在了View.java中,这样一来就很明了了,实现一个监听点击的接口,重写其中的点击函数,这样就可以实现回调的功能。
仿照这种写法,我们也可以在线程间通讯时运用相似的思想。
2.核心代码展示
UI线程:
public class MainActivity extends AppCompatActivity {
private TextView recvTextView;
private Button sendButton;
private SendThread mSendThread = new SendThread();
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uiInit();
//设置接口回调函数
mSendThread.setCallback(new SendThread.onDataChangeListener() {
@Override
public void dataChange(Message msg) {
Message mMsg = Message.obtain();
mMsg = msg;
mHandler.sendMessage(mMsg);
}
});
}
@Override
protected void onStart() {
super.onStart();
//接收msg
mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Toast.makeText(MainActivity.this,""+msg.arg1,Toast.LENGTH_SHORT).show();
recvTextView.setText((String)msg.obj);
break;
default:
Toast.makeText(MainActivity.this,"default",Toast.LENGTH_SHORT).show();
break;
}
}
};
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//启动子线程
mSendThread.start();
}
});
}
public void uiInit() {
recvTextView = findViewById(R.id.recvTextView);
sendButton = findViewById(R.id.sendButton);
}
}
子线程:
public class SendThread extends Thread {
//实例化监听器
private static onDataChangeListener mDataChangeListener = null;
//回调接口
public interface onDataChangeListener {
void dataChange(Message msg);
}
//设置监听器
public void setCallback(onDataChangeListener o) {
mDataChangeListener = o;
}
//数据发生变化时,子线程调用这个函数
private static void onDataChanged(Message msg) {
if (mDataChangeListener != null) {
mDataChangeListener.dataChange(msg);
}
}
public void run() {
Message msg = Message.obtain();
msg.what = 1;
msg.arg1 = 123;
msg.obj = "SendThread发来信息";
onDataChanged(msg);
}
}
3.实现的效果
当我点击一个按钮时,它会启动一个子线程,刷新了UI中的一个TextView同时打了一个Toast显示123。