文档章节

Android 多线程及线程通信

今日竹石
 今日竹石
发布于 2015/04/07 22:51
字数 1979
阅读 198
收藏 9

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

AsyncTask

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

AsyncTask是抽象类.AsyncTask定义了三种泛型类型 ParamsProgressResult。 

  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.   

  3. import java.io.IOException;  

  4.   

  5. import org.apache.http.HttpResponse;  

  6. import org.apache.http.client.ClientProtocolException;  

  7. import org.apache.http.client.HttpClient;  

  8. import org.apache.http.client.methods.HttpGet;  

  9. import org.apache.http.impl.client.DefaultHttpClient;  

  10.   

  11. import android.os.AsyncTask;  

  12. import android.os.Bundle;  

  13. import android.app.Activity;  

  14. import android.view.Menu;  

  15. import android.view.View;  

  16. import android.view.View.OnClickListener;  

  17. import android.widget.Button;  

  18. import android.widget.ImageView;  

  19. import android.widget.ProgressBar;  

  20. import android.widget.Toast;  

  21. import android.graphics.Bitmap;  

  22. import android.graphics.BitmapFactory;  

  23.   

  24. public class Main_Activity extends Activity {  

  25.       

  26.     private ImageView  m_imageView;  

  27.     private Button m_button;  

  28.     private Button m_but;  

  29.     private ProgressBar m_proBar;  

  30.       

  31.     Task task;  

  32.   

  33.     @Override  

  34.     protected void onCreate(Bundle savedInstanceState) {  

  35.         super.onCreate(savedInstanceState);  

  36.         setContentView(R.layout.activity_main);  

  37.           

  38.         m_imageView = (ImageView)findViewById(R.id.imageView);  

  39.         m_button = (Button)findViewById(R.id.download_btn);  

  40.         m_proBar = (ProgressBar)findViewById(R.id.progressBar);  

  41.         m_but = (Button)findViewById(R.id.cancel_btn);  

  42.           

  43.         task = null;  

  44.         m_button.setOnClickListener(new OnClickListener()  

  45.         {  

  46.   

  47.             @Override  

  48.             public void onClick(View v) {  

  49.                 // TODO Auto-generated method stub  

  50.                 task = new Task();  

  51.                 task.execute("http://www.baidu.com/img/shouye_b5486898c692066bd2cbaeda86d74448.gif");  

  52.             }  

  53.               

  54.         });  

  55.         m_but.setOnClickListener(new OnClickListener()  

  56.         {  

  57.   

  58.             @Override  

  59.             public void onClick(View v) {  

  60.                 // TODO Auto-generated method stub  

  61.                 task.cancel(false);  

  62.             }  

  63.         });  

  64.     }  

  65.   

  66.     @Override  

  67.     public boolean onCreateOptionsMenu(Menu menu) {  

  68.         // Inflate the menu; this adds items to the action bar if it is present.  

  69.         getMenuInflater().inflate(R.menu.main_, menu);  

  70.         return true;  

  71.     }  

  72.       

  73.     class Task extends AsyncTask<String,Integer,Bitmap>{  

  74.   

  75.         @Override  

  76.         protected Bitmap doInBackground(String... params) {//处理后台执行的任务,在后台线程执行  

  77.             // TODO Auto-generated method stub  

  78.   

  79.             publishProgress(0);//将会调用onProgressUpdate(Integer... progress)方法    

  80.             HttpClient hc = new DefaultHttpClient();  

  81.             publishProgress(30);  

  82.             HttpGet hg = new HttpGet(params[0]);  

  83.             Bitmap bm = null;                 

  84.               

  85.             HttpResponse hr = null;  

  86.               

  87.             try {  

  88.                 Thread.currentThread().sleep(1000);  

  89.             } catch (InterruptedException e1) {  

  90.                 // TODO Auto-generated catch block  

  91.                 e1.printStackTrace();  

  92.             }  

  93.             if(isCancelled())  

  94.                 return null;  

  95.               

  96.             try {  

  97.                 hr = hc.execute(hg);  

  98.                 bm = BitmapFactory.decodeStream(hr.getEntity().getContent());  

  99.             } catch (ClientProtocolException e) {  

  100.                 // TODO Auto-generated catch block  

  101.                 e.printStackTrace();  

  102.             } catch (IOException e) {  

  103.                 // TODO Auto-generated catch block  

  104.                 e.printStackTrace();  

  105.             }  

  106.             if(isCancelled())  

  107.                 return null;  

  108.               

  109.             publishProgress(100);  

  110.             return bm;  

  111.         }  

  112.           

  113.         protected void onProgressUpdate(Integer... progress) {//在调用publishProgress之后被调用,在ui线程执行  

  114.             m_proBar.setProgress(progress[0]);    

  115.         }    

  116.           

  117.         protected void onPostExecute(Bitmap result) {//后台任务执行完之后被调用,在ui线程执行    

  118.             if(result != null) {    

  119.                 Toast.makeText(Main_Activity.this, "成功获取图片", Toast.LENGTH_LONG).show();    

  120.                 m_imageView.setImageBitmap(result);    

  121.             }else {    

  122.                 Toast.makeText(Main_Activity.this, "获取图片失败", Toast.LENGTH_LONG).show();    

  123.                 m_proBar.setProgress(0);  

  124.             }  

  125.             publishProgress(0);  

  126.         }    

  127.             

  128.         protected void onPreExecute () {//在 doInBackground(Params...)之前被调用,在ui线程执行    

  129.             m_imageView.setImageBitmap(null);    

  130.             m_proBar.setProgress(0);//进度条复位    

  131.         }    

  132.             

  133.         protected void onCancelled () {//在ui线程执行    

  134.             m_proBar.setProgress(0);//进度条复位    

  135.             Toast.makeText(Main_Activity.this, "取消加载", Toast.LENGTH_LONG).show();  

  136.         }    

  137.           

  138.     };  

  139.   

  140. }  


在程序中使用了网络,因此需要在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.   

  3. import android.os.Bundle;  

  4. import android.os.Handler;  

  5. import android.os.HandlerThread;  

  6. import android.os.Looper;  

  7. import android.os.Message;  

  8. import android.annotation.SuppressLint;  

  9. import android.app.Activity;  

  10. import android.util.Log;  

  11. import android.view.Menu;  

  12. import android.view.View;  

  13. import android.widget.Button;  

  14. import android.widget.TextView;  

  15.   

  16. public class MainActivity extends Activity {  

  17.       

  18.     TextView tv;  

  19.     Button but1;  

  20.     Button but2;  

  21.     MyHandler hd, subHd;  

  22.     HandlerThread sub;  

  23.   

  24.     @Override  

  25.     protected void onCreate(Bundle savedInstanceState) {  

  26.         super.onCreate(savedInstanceState);  

  27.         setContentView(R.layout.activity_main);  

  28.           

  29.         tv = (TextView)findViewById(R.id.tv);  

  30.         but1 = (Button)findViewById(R.id.button1);  

  31.         but2 = (Button)findViewById(R.id.button2);  

  32.         hd = new MyHandler();  

  33.           

  34.         but1.setOnClickListener(new View.OnClickListener() {  

  35.               

  36.             @Override  

  37.             public void onClick(View v) {  

  38.                 // TODO Auto-generated method stub  

  39.                 //给主线程自己发送一条消息  

  40.                 hd.sendEmptyMessage(0);  

  41.             }  

  42.         });  

  43.           

  44.         but2.setOnClickListener(new View.OnClickListener() {  

  45.               

  46.             @Override  

  47.             public void onClick(View v) {  

  48.                 // TODO Auto-generated method stub  

  49.                 //新建一个带有Looper的线程  

  50.                 sub = new HandlerThread("sub-thread");   

  51.                 sub.start();  

  52.                   

  53.                 //给子线程关联Handler,并发送一条消息给子线程  

  54.                 subHd = new MyHandler(sub.getLooper());  

  55.                 subHd.sendEmptyMessage(0);  

  56.                   

  57.                 //给子线程发送一个Runnable,在Runnable中发送一条消息给主线程  

  58.                 subHd.post(new Runnable(){  

  59.   

  60.                     @Override  

  61.                     public void run() {  

  62.                         // TODO Auto-generated method stub  

  63.                         //发送一条消息给主线程  

  64.                         hd.sendEmptyMessage(0);  

  65.                     }  

  66.                       

  67.                 });  

  68.             }  

  69.         });  

  70.           

  71.         //终止子线程  

  72.         //subHd.getLooper().quit();  

  73.     }  

  74.       

  75.     @SuppressLint("HandlerLeak")  

  76.     class MyHandler extends Handler{  

  77.           

  78.         public MyHandler() {  

  79.             // TODO Auto-generated constructor stub  

  80.             super();  

  81.         }  

  82.           

  83.         public MyHandler(Looper looper) {  

  84.             // TODO Auto-generated constructor stub  

  85.             super(looper);  

  86.         }  

  87.   

  88.         public void handleMessage(Message msg){  

  89.             switch(msg.what)  

  90.             {  

  91.             case 0:  

  92.                 Log.d(Thread.currentThread().getName(), "msg 0");  

  93.                 break;  

  94.             case 1:  

  95.                 Log.d(Thread.currentThread().getName(), "msg 1");  

  96.                 break;  

  97.             default:  

  98.                 Log.d(Thread.currentThread().getName(), "msg default");  

  99.                 break;  

  100.             }  

  101.         }//handlemsg  

  102.           

  103.     }//MyHandler  

  104.   

  105. }  


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


本文转载自:http://blog.csdn.net/cjjky/article/details/7353390

今日竹石
粉丝 41
博文 227
码字总数 181312
作品 0
朝阳
程序员
私信 提问
Android多线程:这是一份全面 & 详细的HandlerThread学习指南

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的机制的学习指南,内容包括:定性认知、定量使用、工作原理 & 源码分析,希望你们会喜欢。...

Carson_Ho
05/16
0
0
这是一份全面 & 详细的Android多线程知识总结指南

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录 1. 多线程基础知识 在了解Android多线程实现...

Carson_Ho
06/26
0
0
Android:关于多线程的总结知识都在这里了!

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录

Carson_Ho
05/22
0
0
Android面经总结

Basic: 1. 基本的UI控件和布局文件 2. UI配套的Adapter的使用 3. Activity, Intent,Service,broadCast Receiver他们的生命周期管理熟悉一下 4. 操作手机上的数据库SQLite应用 Advanced_1(这是...

晨曦之光
2012/03/09
228
0
Android面经总结

Basic: 1. 基本的UI控件和布局文件 2. UI配套的Adapter的使用 3. Activity, Intent,Service,broadCast Receiver他们的生命周期管理熟悉一下 4. 操作手机上的数据库SQLite应用 Advanced_1(这是...

晨曦之光
2012/03/07
494
0

没有更多内容

加载失败,请刷新页面

加载更多

类比思想歪解Java线程

在操作系统的概念里,有内核态,用户态。其实,操作系统的最小执行单位是进程,而进程是分类型的,有两种类型,内核进程,用户进程。 内核进程由操作系统启动时创建,用户进程是由用户程序启...

萧默
42分钟前
2
0
Git推送错误“ [[远程拒绝]主机->主机(分支当前已签出)”)

昨天,我发布了一个有关如何将Git存储库从我的一台计算机克隆到另一台计算机的问题 , 如何从另一台计算机“ git clone”? 。 现在,我可以成功地将Git存储库从源(192.168.1.2)克隆到目标...

javail
51分钟前
4
0
Selenium 4.0 Alpha更新日志

早在2018年8月,整个测试自动化社区就发生了一件重大新闻:Selenium的创始成员Simon Stewart在班加罗尔Selenium会议上正式确认了Selenium 4的发布日期和一些重要更新。 Selenium 4.0 Alpha版...

八音弦
今天
7
0
2、编写程序求Sn=a+aa+aaa+…+aa…aa的值,其中a是1—9之间的一位数字,n表示 a的位数

//编写程序求Sn=a+aa+aaa+…+aa…aa的值,其中a是1-9之间的一位数字, //n表示 a的位数 #include<stdio.h> int main() { int a,n,i,Sn=0,Z=0; printf("please intput a:\n"); scanf("%d",&a......

201905021729吴建森
今天
5
0
Git中的HEAD是什么?

您会看到Git文档说出类似 分支必须在HEAD中完全合并。 但是到底什么是Git HEAD ? #1楼 了解正确答案的一种好方法是运行git reflog HEAD ,您可以获得HEAD所指向的所有位置的历史记录。 #2楼...

技术盛宴
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部