您的位置:首页 > 移动开发 > Android开发

Android中的 事件流----浅析安卓中的动与静(三) 线程间通讯

2016-10-01 18:00 330 查看
任何程序都是静态代码,我们把这些静态代码打包好,然后放到运行环境当中,通过事件流的驱动使这些代码运行起来。Android的环境也不例外。

静态的代码,在动态事件的驱动下,才会有效的运转起来。

驱动Android程序运行起来的事件大致可以分为以下几种:

用户事件
:如点击屏幕,滑动等各种手势;

系统事件:如屏幕方向的转变;

线程通讯事件:线程之间互发消息,程序根据消息内容进行相应的响应;

进程通讯事件:这里的进程包括本程序开启的进程,也包括其他应用程序的进程。

下面来介绍动态事件驱动的第三种:线程通讯事件流

线程通讯事件流

线程通讯也是造成Android动态化的一个重要方面,当一个UI主线程收到其他线程发过来的消息,可以动态更改自己的页面。

下面总结下线程之间通讯的几种方式

(从重要性和实用角度排序)

1.使用Handler实现

2.使用AsyncTask

3.Activity.runOnUiThread(Runnbale)

4.View.post(Runnbale)

5.View.postDelayed(Runnalbe,long)

2-5其实内部实现都是Handler。

下面一一介绍用法:

1.使用Handler实现

先来讲Handler的实现,因为后边的四个都是基于Handler的实现的,谈到Handler的运行机制,不得不提Looper、Message、MessagerQueue了,它们之间的关系,下边这个图片描述的很清楚了。



用一句话总结就是在主线程中定义Handler对象,然后在子线程中调用这个Handler对象将封装好的Message对象发送到主线程中Looper管理的MessageQueue中。上边两句话是说在子线程中向主线程发送消息。那我如果想从主线程向子线程发送消息呢?或者子线程之间发送消息呢?其实还是一个道理。线程A要想给线程B发送消息,就要获取线程B中的Handler对象,然后通过此对象向线程B中的Looer中的MessageQueue中发送消息。注意,Looper和Handler是一一对应的。一个handler只能向其所在的线程发送Message消息。只不过UI线程的Looper是自动启动好的,其他线程要想享受到Looper的服务,必须通过 Looper.prepare()和Looper.loop();自行启动。下边写了一个demo,以后可以学习参考:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
final Handler mHandler=new Handler();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyButton er=(MyButton) findViewById(R.id.ddd);
Log.v("onCreate",	 "onCreate");
er.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Log.v("onClick",	 v.toString());
Intent sub= new Intent(MainActivity.this, SubActivity.class);
startActivity(sub);

}
});

final Myrunnable murMyrunnable=new Myrunnable();

new Thread(murMyrunnable).start();

new Thread(new Runnable() {

//延迟两秒

public Handler mHandler;

public void run() {

Looper.prepare();
Looper.loop();

mHandler = new Handler() {

public void handleMessage(Message msg) {

Toast.makeText(MainActivity.this, "wewe"+msg.what, Toast.LENGTH_SHORT).show();
}

};

}

}).start();

//创建一个线程

new Thread(new Runnable() {

@Override

public void run() {

//延迟两秒

try {

Thread.sleep( 5000 );

} catch (InterruptedException e) {

e.printStackTrace();

}

mHandler.post(new Runnable() {
//
@Override

public void run() {
er.setText("变了");
Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();
//创建一个线程
Message sdfMessage=new Message();
sdfMessage.what=12 ;
murMyrunnable.mHandler.sendMessage(sdfMessage);
}

});

}

}).start();

//er.setClickable(false);
}

class Myrunnable implements Runnable{

//延迟两秒

public Handler mHandler;

public void run() {

Looper.prepare();

mHandler = new Handler() {

public void handleMessage(Message msg) {

Toast.makeText(MainActivity.this, "wewe"+msg.what, Toast.LENGTH_SHORT).show();
}

};

Looper.loop();

}

}

}


2.使用AsyncTask

关于AsyncTask的使用网上已经有很多资料这里不再详述,只是简单介绍下用法,以及其内部与handler的关系。

AsyncTask屏蔽了很多多线程的实现细节,很适合初学者使用,现在通过代码来介绍:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
final Handler mHandler=new Handler();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyButton er=(MyButton) findViewById(R.id.ddd);
Log.v("onCreate",	 "onCreate");
er.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v){MyAsyncTask myAsyncTask = new MyAsyncTask(MainActivity.this);
myAsyncTask.execute(20);

}
});

}
/*
* integer:启动任务执行的输入参数,integer:后台任务完成的进度值的类型;String:后台执行任务完成后返回结果的类型
* 这三个参数可以根据需要进行设定
*/
class MyAsyncTask extends AsyncTask<Integer, Integer, String>{

ProgressDialog pDialog;
Context mContext;
public  MyAsyncTask( Context mContext){
this.mContext=mContext;
}

//核心函数,可以理解为在子线程中执行
@Override
protected String doInBackground(final Integer... params) {

Integer percent=params[0];

while (percent<101) {
percent++;
publishProgress(percent);
Log.v("percent", percent+"");
}

return null;
}
/*
* 上个函数的结果作为参数,传给result形参,函数内部执行更新UId的更新操作,可以理解为在UI线程中执行
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
/*
* 在执行第一个函数之前执行,做一些准备工作,可以理解为在UI线程中执行
* @see android.os.AsyncTask#onPreExecute()
*/
@Override
protected void onPreExecute() {

//这里的准备工作是显示进度条
pDialog=new ProgressDialog(mContext);
pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pDialog.show();

}
/*
* 可以在第一个函数中调用,更新新进度注意是可以,无需求可以不用使用。
* @see android.os.AsyncTask#onProgressUpdate(java.lang.Object[])
*/
@Override
protected void onProgressUpdate(Integer... values) {

pDialog.setProgress(values[0]);
}
}
 

AsyncTask内部实际上new了一个Handler。如下图:



再来看下InternalHandler的定义:

private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}


显而易见,InternalHandler继承自Handler。

重点不是Handler在哪个类中new的,而是只要是new了Handler,就可以通过Handler向创建Handler的那个线程中发送Message消息。

这就是为什么使用AsyncTask时必须在UI线程中创建的原因。

大概的原来不再赘述,原理与上一部分Handler的运行机制大同小异。

3.Activity.runOnUiThread(Runnbale)

在子线程中调用Activity.runOnUiThread(Runnbale)方法,在传过来的Runnbale参数的run方法里更新主线程UI。具体可以参考以下代码:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MyButton er=(MyButton) findViewById(R.id.ddd);

//创建一个线程

new Thread(new Runnable() {

@Override

public void run() {

//延迟两秒

try {

Thread.sleep( 5000 );

} catch (InterruptedException e) {

e.printStackTrace();

}

runOnUiThread(new Runnable() {

@Override

public void run() {
er.setText("变了");
Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();

}

});

}

}).start();

//er.setClickable(false);
}
}

注意为了保证线程安全,要更改的UI控件必须是final的。为什么说Activity.runOnUiThread(Runnbale)内部是用Handler实现的呢?我们来看下runOnUiThread(Runnbale)的源码就清楚了。

/**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
* not the UI thread, the action is posted to the event queue of the UI thread.
*
* @param action the action to run on the UI thread
*/
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}

看到mHandler对象了吗?我们来看下它的定义:

final Handler mHandler = new Handler();

所以是不是很清楚了。不管Handler在哪个类中new出来,用Handler传值都会传到创建Handler的那个线程中,重点的不是在哪个类中new,而是Handler在哪个线程中。

4.View.post(Runnbale)

其实这个的用法和上边讲的很类似。在子线程中调用某个view的post(Runnbale)方法,在传过来的Runnbale参数的run方法里更新主线程UI。具体可以参考以下代码:

new Thread(new Runnable() {

@Override

public void run() {

//延迟两秒

try {

Thread.sleep( 5000 );

} catch (InterruptedException e) {

e.printStackTrace();

}

er.post(new Runnable() {

@Override

public void run() {
er.setText("变了");
Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();

}

});

}

}).start();

为什么可以这样调用,因为View中也定义了Handler的对象,看下边的源码:



找到mHandler的定义:



5.View.postDelayed(Runnalbe,long)

和上边的类似,无非是延迟一些毫秒数来执行Runnable里面的方法,如View.postDelayed(Runnalbe,2000)是延迟2秒执行。

欢迎大家留言讨论。

后边将介绍造成安卓动态化的第三种因素:进程之间的通讯。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐