Android 多线程及线程通信

AsyncTask

AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。

AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。

  Params 启动任务执行的输入参数,比如HTTP请求的URL。

  Progress 后台任务执行的百分比。

  Result 后台执行任务最终返回的结果,比如String。

AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。

  1) 子类化AsyncTask

  2) 实现AsyncTask中定义的下面一个或几个方法

onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

  1) Task的实例必须在UI thread中创建

  2) execute方法必须在UI thread中调用

  3)不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法

  4)该task只能被执行一次,否则多次调用时将会出现异常

doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

可以调用cancel(boolean)去取消一个任务,在cancel(boolean)调用后,isCancelled()会返回true,并且在doInBackground(Object[])调用后会立即调用onCancelled(Object),而不会去调用onPostExecute(Object)。在调用cancel(boolean)时,如果线程还没有开始执行,那么线程不会去运行;如果线程已经开始运行了,那么mayInterruptIfRunning 标志决定了线程会否应该被中断。因此我们在doInBackground(Object[])中应该定期的检查isCancelled()的值,以保证线程能够快速的中断。

[html] view plaincopy

  1. package com.example.asynctask;
  2. import java.io.IOException;
  3. import org.apache.http.HttpResponse;
  4. import org.apache.http.client.ClientProtocolException;
  5. import org.apache.http.client.HttpClient;
  6. import org.apache.http.client.methods.HttpGet;
  7. import org.apache.http.impl.client.DefaultHttpClient;
  8. import android.os.AsyncTask;
  9. import android.os.Bundle;
  10. import android.app.Activity;
  11. import android.view.Menu;
  12. import android.view.View;
  13. import android.view.View.OnClickListener;
  14. import android.widget.Button;
  15. import android.widget.ImageView;
  16. import android.widget.ProgressBar;
  17. import android.widget.Toast;
  18. import android.graphics.Bitmap;
  19. import android.graphics.BitmapFactory;
  20. public class Main_Activity extends Activity {
  21. private ImageView  m_imageView;
  22. private Button m_button;
  23. private Button m_but;
  24. private ProgressBar m_proBar;
  25. Task task;
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState) {
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.activity_main);
  30. m_imageView = (ImageView)findViewById(R.id.imageView);
  31. m_button = (Button)findViewById(R.id.download_btn);
  32. m_proBar = (ProgressBar)findViewById(R.id.progressBar);
  33. m_but = (Button)findViewById(R.id.cancel_btn);
  34. task = null;
  35. m_button.setOnClickListener(new OnClickListener()
  36. {
  37. @Override
  38. public void onClick(View v) {
  39. // TODO Auto-generated method stub
  40. task = new Task();
  41. task.execute("http://www.baidu.com/img/shouye_b5486898c692066bd2cbaeda86d74448.gif");
  42. }
  43. });
  44. m_but.setOnClickListener(new OnClickListener()
  45. {
  46. @Override
  47. public void onClick(View v) {
  48. // TODO Auto-generated method stub
  49. task.cancel(false);
  50. }
  51. });
  52. }
  53. @Override
  54. public boolean onCreateOptionsMenu(Menu menu) {
  55. // Inflate the menu; this adds items to the action bar if it is present.
  56. getMenuInflater().inflate(R.menu.main_, menu);
  57. return true;
  58. }
  59. class Task extends AsyncTask<String,Integer,Bitmap>{
  60. @Override
  61. protected Bitmap doInBackground(String... params) {//处理后台执行的任务,在后台线程执行
  62. // TODO Auto-generated method stub
  63. publishProgress(0);//将会调用onProgressUpdate(Integer... progress)方法
  64. HttpClient hc = new DefaultHttpClient();
  65. publishProgress(30);
  66. HttpGet hg = new HttpGet(params[0]);
  67. Bitmap bm = null;
  68. HttpResponse hr = null;
  69. try {
  70. Thread.currentThread().sleep(1000);
  71. } catch (InterruptedException e1) {
  72. // TODO Auto-generated catch block
  73. e1.printStackTrace();
  74. }
  75. if(isCancelled())
  76. return null;
  77. try {
  78. hr = hc.execute(hg);
  79. bm = BitmapFactory.decodeStream(hr.getEntity().getContent());
  80. } catch (ClientProtocolException e) {
  81. // TODO Auto-generated catch block
  82. e.printStackTrace();
  83. } catch (IOException e) {
  84. // TODO Auto-generated catch block
  85. e.printStackTrace();
  86. }
  87. if(isCancelled())
  88. return null;
  89. publishProgress(100);
  90. return bm;
  91. }
  92. protected void onProgressUpdate(Integer... progress) {//在调用publishProgress之后被调用,在ui线程执行
  93. m_proBar.setProgress(progress[0]);
  94. }
  95. protected void onPostExecute(Bitmap result) {//后台任务执行完之后被调用,在ui线程执行
  96. if(result != null) {
  97. Toast.makeText(Main_Activity.this, "成功获取图片", Toast.LENGTH_LONG).show();
  98. m_imageView.setImageBitmap(result);
  99. }else {
  100. Toast.makeText(Main_Activity.this, "获取图片失败", Toast.LENGTH_LONG).show();
  101. m_proBar.setProgress(0);
  102. }
  103. publishProgress(0);
  104. }
  105. protected void onPreExecute () {//在 doInBackground(Params...)之前被调用,在ui线程执行
  106. m_imageView.setImageBitmap(null);
  107. m_proBar.setProgress(0);//进度条复位
  108. }
  109. protected void onCancelled () {//在ui线程执行
  110. m_proBar.setProgress(0);//进度条复位
  111. Toast.makeText(Main_Activity.this, "取消加载", Toast.LENGTH_LONG).show();
  112. }
  113. };
  114. }

在程序中使用了网络,因此需要在AndroidManifest.xml添加

[html] view plaincopy

  1. <uses-permission android:name="android.permission.INTERNET"></uses-permission>

Handler

Looper 是消息队列的管理者,消息循环

Handler 是消息的处理者

Message 消息

MessageQueue 消息队列

Handler 只能够关联一个线程的Looper,一个Looper只能管理一个MessageQueue。可以通过关联的Handler向线程发送Message或者Runnable到消息队列中。

[html] view plaincopy

  1. package com.example.handlemsg;
  2. import android.os.Bundle;
  3. import android.os.Handler;
  4. import android.os.HandlerThread;
  5. import android.os.Looper;
  6. import android.os.Message;
  7. import android.annotation.SuppressLint;
  8. import android.app.Activity;
  9. import android.util.Log;
  10. import android.view.Menu;
  11. import android.view.View;
  12. import android.widget.Button;
  13. import android.widget.TextView;
  14. public class MainActivity extends Activity {
  15. TextView tv;
  16. Button but1;
  17. Button but2;
  18. MyHandler hd, subHd;
  19. HandlerThread sub;
  20. @Override
  21. protected void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. setContentView(R.layout.activity_main);
  24. tv = (TextView)findViewById(R.id.tv);
  25. but1 = (Button)findViewById(R.id.button1);
  26. but2 = (Button)findViewById(R.id.button2);
  27. hd = new MyHandler();
  28. but1.setOnClickListener(new View.OnClickListener() {
  29. @Override
  30. public void onClick(View v) {
  31. // TODO Auto-generated method stub
  32. //给主线程自己发送一条消息
  33. hd.sendEmptyMessage(0);
  34. }
  35. });
  36. but2.setOnClickListener(new View.OnClickListener() {
  37. @Override
  38. public void onClick(View v) {
  39. // TODO Auto-generated method stub
  40. //新建一个带有Looper的线程
  41. sub = new HandlerThread("sub-thread");
  42. sub.start();
  43. //给子线程关联Handler,并发送一条消息给子线程
  44. subHd = new MyHandler(sub.getLooper());
  45. subHd.sendEmptyMessage(0);
  46. //给子线程发送一个Runnable,在Runnable中发送一条消息给主线程
  47. subHd.post(new Runnable(){
  48. @Override
  49. public void run() {
  50. // TODO Auto-generated method stub
  51. //发送一条消息给主线程
  52. hd.sendEmptyMessage(0);
  53. }
  54. });
  55. }
  56. });
  57. //终止子线程
  58. //subHd.getLooper().quit();
  59. }
  60. @SuppressLint("HandlerLeak")
  61. class MyHandler extends Handler{
  62. public MyHandler() {
  63. // TODO Auto-generated constructor stub
  64. super();
  65. }
  66. public MyHandler(Looper looper) {
  67. // TODO Auto-generated constructor stub
  68. super(looper);
  69. }
  70. public void handleMessage(Message msg){
  71. switch(msg.what)
  72. {
  73. case 0:
  74. Log.d(Thread.currentThread().getName(), "msg 0");
  75. break;
  76. case 1:
  77. Log.d(Thread.currentThread().getName(), "msg 1");
  78. break;
  79. default:
  80. Log.d(Thread.currentThread().getName(), "msg default");
  81. break;
  82. }
  83. }//handlemsg
  84. }//MyHandler
  85. }

synchronized

1.  synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。

2. synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。

对synchronized(this)的一些理解

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

四、当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

参考:http://blog.csdn.net/cjjky/article/details/7353390

时间: 2024-10-28 11:03:08

Android 多线程及线程通信的相关文章

JavaSE:多线程补充--线程通信

线程通信我认为是多线程中最难掌握的部分了,这里通过两个例子来说明一下. 第一个: 使用两个线程打印 1-100. 线程1, 线程2 交替打印 public class Print implements Runnable{ int i = 1; public void run(){ while(true){ synchronized(this){ if(i<100){ notify(); System.out.println(Thread.currentThread().getName() + &qu

多线程之线程通信条件Condition

Condition是Locks锁下的另一种线程通信之间唤醒.阻塞的实现.它下面的await,和signal能够实现Object下的wait,notify和notifyAll的全部功能,除此之外改监视器和已绑定到每个条件,可以实现多条件的监听.Condition实质是被绑定到一个锁上,腰围特定的Lock实例获得Condition,即用 newCondition()方法. Condition下的await()相对于Object下的wait(); 阻塞或中断之前状况,让其处于等待状态. Conditi

Java多线程之线程通信

线程通信的例子:使用两个线程打印 1-100,线程1.线程2交替打印.涉及到的三个方法:wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器.notify():一旦执行此方法,就会唤醒被wait的一个线程.如果有多个线程被wait,就唤醒优先级高的那个.notifyAll():一旦执行此方法,就会唤醒所有被wait的线程. 说明:1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中.2.wait(),notify(),notifyA

Android多线程操作——线程池管理综述

题记-- 难过了,悄悄走一走: 伤心了,默默睡一觉: 优雅不是训练出来的,而是一种阅历: 淡然不是伪装出来的,而是一种沉淀: 时间飞逝,老去的只是我们的容颜: 时间仿佛一颗灵魂,越来越动人: 1.简述: 在多线程的世界中,是那么的神奇 与 高效以及合理: 2.创建线程池实例 官方推荐使用Executors类工厂方法来创建线程池管理,Executors类是官方提供的一个工厂类,里面封装了好多功能不一样的线程池,从而使得我们创建线程池非常的简单:                    3.使用线程池

AsyncTask、多线程及线程通信

AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单.相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现. AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result. Params 启动任务执行的输入参数,比如HTTP请求的URL. Progress 后台任务执行的百分比. Result 后台执行任务最终返回的结果,比如String. AsyncTask的执行分为四个步骤

多线程之线程通信条件Condition二

接上一篇,实现Condition三个条件,有这样一个应用: 1. 有三个进程,第一个进程运行1次,第二个进程运行2次,第三个进程运行3次: 2. 先运行第二个进程,然后第一个,然后第三个: 3.  依次运行5次循环. 分析: 此时若用Object的wait和notify是实现不了的,我们能够用Lock锁的Condition实现,我们须要定义三个信号条件,分别控制这三个进程. 实现例如以下: package andy.thread.test; import java.util.concurrent

java 多线程 day04 线程通信

package com.czbk.thread; /** * Created by chengtao on 17/12/3. * 需求: 子线程先运行10次,然后主线程运行 100次,依次运行50次 * wait(): 等待 如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒. notify(): 唤醒 唤醒线程池等待线程其中的一个. notifyAll() : 唤醒线程池所有等待 线程. wait与notify方法要注意的事项:

Android线程管理&mdash;&mdash;线程通信

线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用.本小节主要从以下三个方面进行分析: <Android线程管理--线程通信> <Android线程管理--ActivityThread> <Android线程管理--Thread> 一.Handler.MessageQueue.Message及Looper四者的关系 在开发A

Android线程管理(一)——线程通信

一.Handler.MessageQueue.Message及Looper四者的关系 在开发Android多线程应用时,Handler.MessageQueue.Message及Looper是老生常谈的话题.但想彻底理清它们之间的关系,却需要深入的研究下它们各自的实现才行.首先,给出一张它们之间的关系图: Looper依赖于MessageQueue和Thread,因为每个Thread只对应一个Looper,每个Looper只对应一个MessageQueue. MessageQueue依赖于Mes