ANR,多线程,Handler,异步加载

来源:互联网 发布:ubuntu的vim怎么装不了 编辑:程序博客网 时间:2024/06/11 19:50

一、ANR(Application Not Responding)

1.什么是ANR异常?
——指应用程序无响应。android程序中会弹出提示dialog,其中一个选项是“等待”,另一个选项是“强制退出”。
2.什么情况下会引发ANR异常?
——android应用程序的响应由ActivityManager和WindowManager来管理和监听。
1)在5秒钟之内没有相应输入事件(如返回键,屏幕触摸)
2)广播在10秒钟之内没有完成逻辑
实际应用中什么情况下会出现ANR:在主线程中执行耗时操作(如文件下载,图片下载,IO异常,数据库操作,高耗时的图片尺寸处理,复杂的视图加载等等)
3.如何解决?
——1)把耗时操作相关的代码写到子线程。(要求主线程的生命周期的方法尽量少做事情)。在android程序中提供了handler+message消息机制,使子线程能够与主线程进行通信。
——2)应用程序应避免在广播(BroadcastReceiver)中执行耗时操作或计算。但不是在子线程中做这些任务(因为BroadcastReceiver生命周期短),如果在intent广播中需要执行耗时操作,可以启动service去做。
——3)避免在intent receiver中启动activity,因为activity会创建新的视图,并且在用户正在运行的应用程序上抢占焦点。如果你的应用程序在相应intent广播时需要向用户展示什么,这个时候应该使用android提供的Notification Manager,把它发到通知栏上,让用户选择是否查看,而不是程序自己打开。因为这样会很卡,造成用户无法点击,用户体验会很差。

二、线程

1.操作系统:实时操作系统,分时操作系统(可以并发做多个任务)。从微观的角度看,操作系统还是实时的,cpu一次只能处理一件事情。但是因为cpu的执行速度是很快的。
2.什么是进程?
——(操作系统)为每一个任务分配一系列的资源(如cpu,内存等)来执行该任务,这就是进程。
3.什么是线程?
——CPU执行的最小的代码段
4.进程与线程的关系?
——进程是炒菜,线程是炒菜的每一个步骤。进程中包含很多线程。

三、Handler

一个Handler允许你发message和runnable对象。每个Handler实例都会关联一个单线程和线程消息队列,当你创建一个新的Hanlder,它就被绑定到当前所在的线程——从那时起,它将提供消息和runnable对象,当消息或runnable从消息队列里面被取出的时候,就会被执行。
一个Handler有两个主要用途:
1)执行调度消息和将要被执行的runnable
2)运行在某个线程上,共享线程的消息队列

四、异步加载(AsyncTask)

这里我们来做一个下载图片的demo。
1.首先写一个MyAsyncTask类继承AsyncTask。

public class MyAsyncTask extends AsyncTask<String,Integer,Bitmap>{        @Override        protected Bitmap doInBackground(String... params) {            return null;        }    }

代码解析:这里我们注意到AsyncTask后面带的三个参数类型——Params:输入参数(请求参数,图片url等);Progress:进度(异步任务执行的过程);Result:结果(异步任务执行完成后返回的结果)。实现的doInBackground方法通常用来执行后台任务,其会在子线程中进行。0
2.几个重要的方法实现
——onPreExecute方法:执行异步任务之前的预处理,在主线程中执行
——onProgressUpdate:更新加载进度
——onPostExecute:异步任务完成后需要处理返回的结果
3.布局文件:TextView用于显示下载的进度百分比,ProgressBar就是下载的动态进度更新,ImageView显示下载的图片。

    <TextView        android:id="@+id/tv_progress"        android:text="@string/hello_world"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:textSize="24sp"/>    <ProgressBar        android:id="@+id/pb"        android:layout_width="match_parent"        android:layout_height="wrap_content"        style="@android:style/Widget.ProgressBar.Horizontal"/>    <Button        android:id="@+id/btn_download"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="开始下载"        android:textSize="20sp"/>    <ImageView        android:id="@+id/iv_image"        android:layout_width="match_parentm"        android:layout_height="match_parent"        android:scaleType="center"/>

4.点击下载按钮我们要开启异步任务。这里传的url就是图片的地址。

MyAsyncTask myAsyncTask = new MyAsyncTask();myAsyncTask.execute(url);

5.在doInBackground方法中进行下载图片的相关操作。

@Override        protected Bitmap doInBackground(String... params) {            Bitmap bitmap = null;            try {                //获取URL对象                URL url = new URL(params[0]);                //打开连接                HttpURLConnection connection = (HttpURLConnection) url.openConnection();                //设置请求方式                connection.setRequestMethod("GET");                //设置连接超时                connection.setConnectTimeout(5000);                if (connection.getResponseCode()==200){                    //获取文件长度                    maxLength = connection.getContentLength();                    //设置进度条最大进度                    progressBar.setMax(maxLength);                    //得到图片流                    InputStream inputStream = connection.getInputStream();                    bitmap = BitmapFactory.decodeStream(inputStream);                }            } catch (Exception e) {                e.printStackTrace();            }            return bitmap;        }

6.在onPostExecute(Bitmap bitmap)方法中把异步任务处理的结果(图片)设置到ImageView上。

@Override        protected void onPostExecute(Bitmap bitmap) {            super.onPostExecute(bitmap);            imageView.setImageBitmap(bitmap);        }

7.记得加权限。

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

到这里其实已经可以把图片显示出来,但是加载进度条还没做。OK来做进度条。这里的做法是将图片下载到本地,再读取。

String fileName =imageUrl.substring(imageUrl.lastIndexOf("/")+1);FileOutputStream fileOutputStream = new FileOutputStream(SD_CARD_PATH+"/"+fileName);int len = 0;byte[] buffer = new byte[1024];while ((len = inputStream.read(buffer))!=-1){       fileOutputStream.write(buffer,0,len);       //更新进度       publishProgress(len);       }fileOutputStream.close();inputStream.close();bitmap=BitmapFactory.decodeFile(SD_CARD_PATH+"/"+fileName);

然后,我们在onProgressUpdate方法里面把加载进度text设上。

@Override        protected void onProgressUpdate(Integer... values) {            super.onProgressUpdate(values);            progressBar.setProgress(progressBar.getProgress()+values[0]);            String text = "下载进度:"+100*progressBar.getProgress()/maxLength+"%";            progressTV.setText(text);        }

大功告成。

0 0