1.Android中的线程概括
- 线程与进程
线程:线程是CPU调度的最小单元,同时线程也是一种有限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁有开销
进程:一般指一个执行单元,在pc和移动设备上指的是一个程序或者一个应用。 - 主线程和子线程
主线程:指的是进程所拥有的线程,在java中默认情况下一个进程只有一个线程,这个线程就是主线程
子线程:工作线程,除了主线程以外的都是子线程
Android的线程模型和java线程模型一样,也分为主线程和子线程,其中主线程叫做UI线程,主线程主要作用是运行四大组件以及处理和用户的交互,子线程的作用是处理耗时任务,比如说网络请求数据或者IO操作。
从Android3.0开始系统要求网络访问必须在子线程中进行,否则将抛出异常NetworkOnMainThreadException,这样做避免了主线程因耗时操作所阻塞从而出现ANR
2.Android中的线程——AsyncTask
AsyncTask是一个轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI,AsyncTask封装了Thread和Handler,AsyncTask并不适合做特别耗时的任务。
下面给出一个用AsyncTask下载图片并显示进度的例子
MainActivity.Java
package com.zhoujian.thread;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import butterknife.ButterKnife;
import butterknife.InjectView;
public class MainActivity extends Activity
{
@InjectView(R.id.download)
Button mDownload;
@InjectView(R.id.img)
ImageView mImg;
private MyDownLoadAsynctask mAsynctask;
private ProgressDialog progressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
clickEvent();
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("提示信息");
progressDialog.setMessage("正在下载,请稍后...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCanceledOnTouchOutside(false);
}
private void clickEvent()
{
mDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAsynctask = new MyDownLoadAsynctask();
mAsynctask.execute("http://img04.muzhiwan.com/2015/06/16/upload_557fd293326f5.jpg");
}
});
}
class MyDownLoadAsynctask extends AsyncTask
{
/**
* 在主线程中执行,异步任务执行之前会调用,一般用于做一些准备工作
*/
@Override
protected void onPreExecute()
{
Toast.makeText(MainActivity.this, "异步任务开始执行下载", Toast.LENGTH_SHORT).show();
progressDialog.show();
}
/**
* 在线程池中执行,用于执行异步任务
* @param strings
* @return
*/
@Override
protected Bitmap doInBackground(String... strings) {
HttpURLConnection connection = null;
try {
URL url = new URL(strings[0]);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setConnectTimeout(5000);
int code = connection.getResponseCode();
if (code == 200) {
InputStream is = connection.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int length = -1;
int progress = 0;
int count = connection.getContentLength();
byte[] bytes = new byte[1024];
while ((length = is.read(bytes)) != -1) {
progress += length;
if (count == 0) {
publishProgress(-1);
} else {
//进度值改变通知,会调用onProgressUpdate()方法
publishProgress((int) ((float) progress / count * 100));
}
if (isCancelled()) {
return null;
}
Thread.sleep(50);
bos.write(bytes, 0, length);
}
return BitmapFactory.decodeByteArray(bos.toByteArray(), 0, bos.size());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
/**
* 异步任务执行之后,会调用该方法,此方法会返回后台任务的返回值,即doInBackground的返回值
* @param bitmap
*/
@Override
protected void onPostExecute(Bitmap bitmap)
{
Toast.makeText(MainActivity.this, "图片下载完成", Toast.LENGTH_SHORT).show();
mImg.setImageBitmap(bitmap);
progressDialog.dismiss();
}
/**
* 在主线程中执行,当后台任务的执行进度发生改变时会调用这个方法
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values)
{
int progress = values[0];
if (progress != -1) {
progressDialog.setProgress(progress);
}
}
}
}
activity_main.xml
AsyncTask使用时的注意事项:
(1)AsyncTask必须在主线程中创建,在子线程中创建会报错
报错截图如下:
看到这个错误,相信大家看着应该很熟悉,这个错误正是Handler在子线程创建的时候报的错。因为AsyncTask内部封装了Handler和Thread
(2)execute方法也必须在主线程中调用
(3)一个AsyncTask对象只能调用一次execute方法,否则会报错
报错截图如下:
(4)(0 到Android1.6)AsyncTask是串行执行任务的
[1.6到3.0)AsyncTask是并行执行任务的
[3.0到以后]AsyncTask是串行执行任务的,但是也可以通过executeOnExecutor方法来并行执行任务
3.Android中的线程——HandlerThread
HandlerThread继承了Thread,是一种可以使用Handler的thread
HandlerThread内部创建了消息队列,外界需要通过Handler的消息方式来通知HandlerThread执行一个具体的任务,可能还是好理解,直接上demo
SecondActivity.java
package com.zhoujian.thread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.text.Html;
import android.widget.TextView;
/**
* Created by zhoujian on 2016/12/15.
*/
public class SecondActivity extends Activity
{
private static final int MSG_UPDATE_INFO = 0;
private static final int MSG_INFO = 1;
private TextView textview;
private HandlerThread mHandlerThread;
private Handler handler;
private boolean boleanFlag;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_INFO:
String result = "随机数:%d";
result = String.format(result, (int) (Math.random() * 10));
textview.setText(Html.fromHtml(result));
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
//创建后台线程
myThread();
textview = (TextView) findViewById(R.id.textview);
}
@Override
protected void onResume()
{
super.onResume();
boleanFlag = true;
handler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protected void onPause()
{
super.onPause();
boleanFlag = false;
handler.removeMessages(MSG_UPDATE_INFO);
}
private void myThread()
{
mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
handler = new Handler(mHandlerThread.getLooper())
{
@Override
public void handleMessage(Message msg)
{
try
{
//模拟耗时操作
Thread.sleep(2000);
mHandler.sendEmptyMessage(MSG_INFO);
} catch (InterruptedException e)
{
e.printStackTrace();
}
if (boleanFlag)
{
handler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
}
}
};
}
@Override
protected void onDestroy()
{
super.onDestroy();
//释放资源
mHandlerThread.quit();
}
}
activity_second.xml
运行结果截图:
4.Android中的线程——IntentService
IntentService是一种特殊的Service,它继承了Service并且是一个抽象类。IntentService可用于执行后台耗时任务,当任务执行完后会自动停止,同时由于IntentService是服务,所以它的优先级比单纯的线程要高,不容易被系统杀死。
5. Android中的线程——Thread
两种创建线程的方式: