1 AsyncTask异步任务
Application Not Responding,应用程序无响应
Android系统规定只有UI线程(主线程)能够修改UI界面,但是如果在UI线程中执行耗时操作,则会导致线程阻塞,影响用户体验,如果耗时操作导致阻塞时间过长,则有可能会引起系统ANR
产生的原因
用户在界面上的操作是由主线程处理,如果主线程被阻塞,那么就没有办法响应用户的操作,这时候可以看做是程序就“卡住了”,如果阻塞超过5秒,就会导致ANR。
如何避免ANR?
我们只需要将会造成主线程阻塞的操作(耗时操作)放在子线程中就可以了。
注意事项
1、超过5秒没有响应用户操作才会导致ANR,那么是不是5秒之内的耗时操作就可以在主线程中执行?
不是的,即使没有导致ANR也会影响用户的体验,一般200ms以上的操作都属于耗时操作应该放在子线程中执行
1、 ANR的产生不只是因为主线程被阻塞,根本的原因是程序没有响应用户的操作超过5秒,才会导致ANR。
但是,Android系统规定,和界面UI更新相关的操作必须在主线程中执行,如果在子线程中对UI界面进行更新操作,就会抛出异常,导致程序奔溃。
异常信息:android.view.ViewRootImpl$CalledFromWrongThreadException: Only theoriginal thread that created a view hierarchy can touch its views.
问题:执行耗时操作需要在子线程中完成,但是子线程不能更新UI,怎么办?
答:Android提供了消息机制可能解决这个问题,原理就是子线程中如果需要更新UI,就“通知”主线程更新UI
Android提供了以下方式解决上面的问题:
1、Handler消息机制(后面讲)
2、AsyncTask异步任务
【
MainThread 主线程(UI线程):应用启动时创建,处理与UI相关事情,如点击事件、数据更新
WorkThread 子线程(工作线程):Android 4.0之后UI线程不能访问网络资源或执行耗时操作,必须开启子线程
】
【
Android提供的异步任务类,主要作用是可以在子线程中执行耗时操作,并通知主线程更新UI
功能
在类中实现异步操作,并提供回调方法反馈当前异步执行的程度,最后将反馈的结果提供给UI主线程
回调方法
1.onPreExecute: 线程任务开始执行前的准备工作(运行在主线程中)
2.doInBackground:在子线程中执行耗时操作, 在线程中执行的代码(后台开启了线程并执行这部分代码)
3.onProgressUpdate: 在线程的执行中需要执行的界面操作(运行在主线程中)
4.onPostExecute:在子线程直线完毕之后调用(在主线程中执行)
其它回调方法:
5.onCancelled()是当调用cancel方法取消任务并doInBackground执行完之后才会调用
常用方法
execute:执行任务
cancel(boolean):取消任务
isCancelled():判断当前任务是否被取消
publishProgress(int progressValue):发布任务进度
三个泛型参数
第一个泛型参数:(定义)是传递给doInBackground方法的参数的类型(引用类型),由execute(…..)方法初传入
第二个泛型参数:(定义)是传递给onProgressUpdate方法的参数的类型,由publishProgress(。。。。。)方法传入
第三个泛型参数:是传递给onPostExecute方法的参数的类型,接收的是doInBackground方法的返回值
基本使用步骤
1、定义一个类,继承自AsyncTask,并指定三个泛型
2、重写回调方法
3、在UI线程中实例化AsyncTask对象
4、在UI线程中,执行AsyncTask对象的execute(..)方法,开始执行异步任务
5、在执行过程中,可以通过调用cancel(true)方法,停止异步任务
使用AsyncTask必须遵守的准则
三个泛型使用位置
第一个泛型:在doInBackground()方法中使用
第二个泛型:在onProgressUpdate()方法中使用
第三个泛型:在onPostExecute()方法中使用
AsyncTask的实例必须在UIthread中创建
execute方法必须在UI线程中被调用
一个AsyncTask实例只能被执行一次,否则多次调用时将会出现异常
】
【
MarkdownPad --:用于看.md文件格式的文档工具。
Volley、XUtils、Universal-Image-Loader、okhttp、SlidingMenu、android-async-http、fresco
ButterKnife、EventBus
】
【
publicclassMainActivityextendsActivity {
@ViewInject(R.id.iv)ImageViewiv;
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
publicvoiddownloadImage(View v){
//下载图片
HttpUtilshttpUtils =newHttpUtils();
Stringurl ="http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
httpUtils.send(HttpMethod.GET, url,newRequestCallBack() {
@Override
publicvoidonFailure(HttpException arg0, String arg1) {
}
@Override
publicvoidonSuccess(ResponseInfo arg0) {
Toast.makeText(MainActivity.this, arg0.result,0).show();
}
});
}
}
】
【
当有多个异步任务被同时启动时,那么是多个同时执行还是依次排队执行??
当有多个异步任务通过execute方法被同时启动时,是依次排队执行的,即
只有当第一个启动被启动的异步任务执行完毕后才会去执行下一个
如何实现让多条异步任务同时执行??
1.当多个异步对象通过execute方法启动时,
* 特点:不管异步任务对象是否属于同类别,使用都保持依次排队执行的特点
2. 如果需要让多个异步任务同时执行的话,可以选择使用
*executeOnExecutor方法启动异步任务
* 参数:
* 1:Executor线程池对象,可以通过此对象指定同时可以有多少个异步任务一起运行
* 2:作用与execute方法中的参数作用完全一致
* 注意:此处的数字不要添加的太多,否则影响速度
指定同时执行3条异步任务,代码如:
Executorexec= Executors.newFixedThreadPool(3);
newMyTask().executeOnExecutor(exec,pb);
newMyTask().executeOnExecutor(exec,pb2);
newMyTask().executeOnExecutor(exec,pb3);
】
【
publicclassMainActivityextendsActivity {
privateProgressBarpb,pb2,pb3;
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
initView();
}
privatevoidinitView() {
pb= (ProgressBar)this.findViewById(R.id.progressBar1);
pb2= (ProgressBar)this.findViewById(R.id.progressBar2);
pb3= (ProgressBar)this.findViewById(R.id.progressBar3);
}
publicvoidbtnClick(View v){
Executor exec = Executors.newFixedThreadPool(3);//同时执行的线程数
new MyTask().executeOnExecutor(exec,pb);
new MyTask().executeOnExecutor(exec,pb2);
new MyTask().executeOnExecutor(exec,pb3);
}
//异步任务
classMyTaskextendsAsyncTask{
ProgressBarcurrentPb;
@Override
protectedVoid doInBackground(ProgressBar...params) {
//TODOAuto-generated method stub
currentPb= params[0];
for(inti=0;i<=100;i++){
try{
Thread.sleep(100);
publishProgress(i);
}catch(InterruptedException e) {
//TODOAuto-generated catch block
e.printStackTrace();
}
}
returnnull;
}
@Override
protectedvoidonProgressUpdate(Integer... values) {
//TODOAuto-generated method stub
super.onProgressUpdate(values);
currentPb.setProgress(values[0]);
}
}
}
】
【
publicclassTwoActivityextendsActivity {
/*
*实现多张图片同时下载并且在图片下载过程中时刻显示图片的下载进度
*/
ImageViewiv,iv2,iv3;
ProgressBarpb,pb2,pb3;
String[]urls= {
"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png",
"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png",
"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png"};
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
//TODOAuto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.two);
initView();
}
privatevoidinitView() {
iv= (ImageView) findViewById(R.id.imageView1);
iv2= (ImageView) findViewById(R.id.imageView2);
iv3= (ImageView) findViewById(R.id.imageView3);
pb= (ProgressBar) findViewById(R.id.progressBar1);
pb2= (ProgressBar) findViewById(R.id.progressBar2);
pb3= (ProgressBar) findViewById(R.id.progressBar3);
}
publicvoidclick(View v) {
Executor exec = Executors.newFixedThreadPool(2);
newImageTask().executeOnExecutor(exec,urls[0],iv,pb);
newImageTask().executeOnExecutor(exec,urls[1],iv2,pb2);
newImageTask().executeOnExecutor(exec,urls[2],iv3,pb3);
}
classImageTaskextendsAsyncTask {
ImageViewcurrentIv;
ProgressBarcurrentPb;
@Override
protectedBitmap doInBackground(Object...params) {
//TODOAuto-generated method stub
Stringurl = (String) params[0];
currentIv= (ImageView) params[1];
currentPb= (ProgressBar) params[2];
try{
HttpURLConnectionconn = (HttpURLConnection)newURL(url)
.openConnection();
conn.setRequestMethod("GET");
conn.connect();
if(conn.getResponseCode() == 200) {
InputStreamis = conn.getInputStream();
byte[] b =newbyte[1024];
intnum = -1;
ByteArrayOutputStreambos =newByteArrayOutputStream();
intcurrent = 0;
inttotal = conn.getContentLength();
while((num = is.read(b)) != -1) {
bos.write(b,0, num);
SystemClock.sleep(100);
current+= num;
publishProgress(total, current);
}
byte[]bitm = bos.toByteArray();
returnBitmapFactory.decodeByteArray(bitm,0, bitm.length);
}
}catch(MalformedURLException e) {
//TODOAuto-generated catch block
e.printStackTrace();
}catch(IOException e) {
//TODOAuto-generated catch block
e.printStackTrace();
}
returnnull;
}
@Override
protectedvoidonProgressUpdate(Integer... values) {
//TODOAuto-generated method stub
super.onProgressUpdate(values);
currentPb.setMax(values[0]);
currentPb.setProgress(values[1]);
}
@Override
protectedvoidonPostExecute(Bitmap result) {
//TODOAuto-generated method stub
super.onPostExecute(result);
if(result !=null){
currentIv.setImageBitmap(result);
}
}
}
}
】
【
publicclassMainActivityextendsActivity {
privateTextViewtv_count;
privateintcount= 0;
privateCountTaskcountTask;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_count= (TextView)this.findViewById(R.id.tv_count);
}
//开始计数
publicvoidstartCount(View v) {
if(countTask==null) {
countTask=newCountTask();
countTask.execute();
}
}
//暂停
publicvoidpauseCount(View v) {
if(countTask!=null) {
countTask.cancel(true);
countTask=null;
}
}
//重置
publicvoidreset(View v) {
pauseCount(null);
count= 0;
tv_count.setText("00:00:00");
}
//开启异步任务
privateclassCountTaskextendsAsyncTask {
@Override
protectedVoid doInBackground(Void... params){
while(!isCancelled()) {
try{
Thread.sleep(10);
//通知主线程更新显示
publishProgress(++count);
}catch(InterruptedException e) {
//TODOAuto-generated catch block
e.printStackTrace();
break;
}
}
returnnull;
}
@Override
protectedvoidonProgressUpdate(Integer... values) {
if(isCancelled()) {
return;
}
intss = values[0];
intmm = values[0] / 60;
inthh = values[0] / 60 / 60;
// tv_count.setText(values[0]+"");
tv_count.setText(hh +":"+ mm +":"+ ss);
}
//当子线程成功执行之后调用
@Override
protectedvoidonPostExecute(Void result) {
Log.i("mtag","onPostExecute");
Toast.makeText(MainActivity.this,"onPostExecute",0).show();
}
//当被中断取消时调用
@Override
protectedvoidonCancelled() {
Log.i("mtag","onCancelled");
}
}
}
】
Android4.0开始,Android系统规定不能在UI线程中执行访问网络资源的操作,相关操作必须在子线程中完成
Android网络访问需要的权限:android.permission.INTERNET
【
/**
* 网络访问工具类
*
*@authorEvanYu
*@date2016.01.08
*/
publicclassHttpUtils {
/**
* 网络访问超时时间
*/
publicstaticfinalintTIMEOUT= 10000;
/**
* 通过get方式实现网络请求
*
*@paramurl
* 访问的url地址
*@return请求的结果,null代表请求失败
*/
publicstaticbyte[] doGet(String url) {
HttpURLConnection conn =null;
try{
URL mUrl =newURL(url);
conn = (HttpURLConnection)mUrl.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(TIMEOUT);
conn.setReadTimeout(TIMEOUT);
conn.connect();
intcode= conn.getResponseCode();
if(code== 200) {
returnreadStream(conn.getInputStream());
}else{
thrownewRuntimeException("网络访问失败:"+ code);
}
}catch(Exception e) {
e.printStackTrace();
returnnull;
}finally{
if(conn!=null) {
conn.disconnect();
conn =null;
}
}
}
publicstaticbyte[] doPost(String url, String params) {
HttpURLConnection conn =null;
try{
URL mUrl =newURL(url);
conn = (HttpURLConnection)mUrl.openConnection();
conn.setRequestMethod("POST");
conn.setConnectTimeout(TIMEOUT);
conn.setReadTimeout(TIMEOUT);
//设置请求属性
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", params.length() +"");
// Post请求必须要写以下两行代码
conn.setDoInput(true);
conn.setDoOutput(true);
//将请求参数写到请求体中
conn.getOutputStream().write(params.getBytes());
;
conn.connect();
intcode= conn.getResponseCode();
if(code== 200) {
returnreadStream(conn.getInputStream());
}else{
thrownewRuntimeException("网络访问失败:"+ code);
}
}catch(Exception e) {
e.printStackTrace();
returnnull;
}finally{
if(conn!=null) {
conn.disconnect();
conn =null;
}
}
}
privatestaticbyte[] readStream(InputStream is)throwsIOException {
ByteArrayOutputStream baos =newByteArrayOutputStream();
byte[] buf =newbyte[1024];
intlen = 0;
while((len = is.read(buf)) != -1) {
baos.write(buf, 0, len);
}
returnbaos.toByteArray();
}
}
】
使用ProgressBar控件显示下载进度
使用ProgressDialog显示下载进度
构造方法:ProgressDialog(Contextcontext)
设置进度条样式:setProgressStyle(intstyle)
设置标题:setTitle(CharSequence)
设置标题图标:setIcon(intresId)
设置显示内容:setMessage(CharSequencemessage)
设置进度值:setProgress(intvalue)
显示对话框:show()
关闭对话框:cancel()
【
publicclassMainActivityextendsActivity {
privateImageViewimg_view;
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img_view= (ImageView)this.findViewById(R.id.img_view);
}
publicvoiddownloadImg(View v) {
// Stringurl=
//"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png";
Stringurl ="http://img1.imgtn.bdimg.com/it/u=335355609,381250936&fm=21&gp=0.jpg";
newMyAsynTask().execute(url);
}
privateclassMyAsynTaskextendsAsyncTask {
ProgressDialog pDialog;
@Override
protectedvoidonPreExecute() {
//开始下载之前先显示一个对话框
pDialog=newProgressDialog(MainActivity.this);
pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pDialog.setMax(100);
pDialog.setTitle("下载图片");
pDialog.setMessage("正在下载图片.....");
pDialog.show();
}
@Override
protectedBitmap doInBackground(String...params) {
/*
* Stringurl=params[0]; byte[]data = HttpUtils.doGet(url);
* //将下载到的数据解析成一张图片Bitmapbm=BitmapFactory.decodeByteArray(data,
* 0, data.length); SystemClock.sleep(2000);returnbm;
*/
HttpURLConnectionconn =null;
try{
Stringurl = params[0];
URLmurl =newURL(url);
conn= (HttpURLConnection) murl.openConnection();
conn.setRequestMethod("GET");
intcode = conn.getResponseCode();
if(code == 200) {
//获取数据的总大小
inttatalSize = conn.getContentLength();
floatcurSize = 0;//记录当前已经下载的大小
InputStreamis = conn.getInputStream();
ByteArrayOutputStreambaos =newByteArrayOutputStream();
byte[] buf =newbyte[10];
intlength = 0;
while((length = is.read(buf)) != -1) {
baos.write(buf,0, length);
curSize+= length;
publishProgress((int) ((curSize / tatalSize) * 100));
//模拟耗时操作
SystemClock.sleep(20);
}
//将下载到的数据解析成一张图片
byte[]data = baos.toByteArray();
Bitmapbm = BitmapFactory.decodeByteArray(data, 0,
data.length);
returnbm;
}else{
thrownewRuntimeException("网路访问失败"+ code);
}
}catch(Exception e) {
e.printStackTrace();
}finally{
if(conn !=null){
conn.disconnect();
conn=null;
}
}
returnnull;
}
@Override
protectedvoidonProgressUpdate(Integer... values) {
pDialog.setProgress(values[0]);
}
@Override
protectedvoidonPostExecute(Bitmap result) {
img_view.setImageBitmap(result);
//取消显示
// pDialog.dismiss();
pDialog.cancel();
}
}
}
】
数据网:K780数据网、聚合数据等
K780测试账号
Appkey:15250
Secret:2bbebb3e480a850df6daca0c04a954e1
Sign:f88a5cecc3cbd37129bc090c0ae29943
网络访问工具类的封装
HttpUtils类
K780数据访问工具类的封装
K780Utils类
【
public classWeather {
privateStringdays;
privateStringtemperature;
publicWeather() {
}
publicWeather(String day, String temperature) {
this.days= day;
this.temperature= temperature;
}
publicString getDay() {
returndays;
}
public voidsetDay(String day) {
this.days= day;
}
publicString getTemperature() {
returntemperature;
}
public voidsetTemperature(String temperature) {
this.temperature= temperature;
}
@Override
publicString toString() {
return"Weather[day="+days+", temperature="+temperature+"]";
}
}
引入网络访问工具类
publicclassMainActivityextendsActivity {
privateTextViewtv_show;
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_show= (TextView) findViewById(R.id.tv_show);
}
publicvoiddownload(View v) {
Stringurl ="http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=15250&sign=f88a5cecc3cbd37129bc090c0ae29943&format=json";
newMyTask().execute(url);
}
privateclassMyTaskextendsAsyncTask> {
@Override
protectedListdoInBackground(String... params) {
Stringdata;
try{
Listlist =newArrayList();
data=newString(HttpUtils.doGet(params[0]));
JSONObjectjsonObject =newJSONObject(data);
JSONArrayresult = jsonObject.getJSONArray("result");
for(inti = 0; i < result.length(); i++) {
JSONObjecttemp = result.getJSONObject(i);
Stringdays = temp.getString("days");
Stringtemperature = temp.getString("temperature");
list.add(newWeather(days, temperature));
}
returnlist;
}catch(JSONException e) {
//TODOAuto-generated catch block
e.printStackTrace();
}
returnnull;
}
@Override
protectedvoidonPostExecute(List result) {
// tv_show.setText(result);
for(Weather weather : result) {
tv_show.append(weather.toString() +"\n");
}
}
}
}
】