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

任何程序都是静态代码,我们把这些静态代码打包好,然后放到运行环境当中,通过事件流的驱动使这些代码运行起来。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秒执行。

 

欢迎大家留言讨论。

后边将介绍造成安卓动态化的第三种因素:进程之间的通讯。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一步一台阶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值