ANR产生的原理以及处理的案例
ANR : application not response 应用程序无响应
产生的原因:主线程 需要做很多重要的事情:响应点击事件,
更新UI等
如果在主线程i面阻塞过久的时间应用程序会无响应。
为了避免应用程序出现anr,所有的耗时的操作都应该放在子线程
里面执行。
如果将上一章的请求网络图片以及图片的显示直接放在子线程里将
将报错。原因:只有主线程才能更新UI。主要代码应该修改为:
public void click(View view){
final String path = et_path.getText().toString().trim();
if(TextUtils.isEmpty(path)){
Toast.makeText(this, "图片路径不能为空", 0 ).show();
}else{
new Thread(){
public void run(){
//连接服务器 get 请求获取图片
try{
URL url = new URL(path);
//根据url 发送http 的请求
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求的方式
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
//得到服务器返回的相应码
int code = conn.getResponseCode();
if(code == 200){
InputStream is = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
//告诉主线程一个消息 帮我修改界面,内容:bitmap
Message msg = new Message();
msg.what = CHANGE_UI; //可任意附一个值给它,比如1
msg.obj = bitmap;
handler.sendMessage(msg);
}else{
Message msg = new Message();
msg.what = ERROR; //可任意附一个值给它,比如0
handler.sendMessage(msg);
}
}catch(Exception e){
Message msg = new Message();
msg.what = ERROR; //可任意附一个值给它,比如0
handler.sendMessage(msg);
}
}
}
}
}
//主线程中创建消息处理器
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg){
if(msg.what == CHANGE_UI){
Bitmap bitmap = (Bitmap) msg.obj;
iv.setImageBitmap(bitmap);
}else if(msg.what == ERROR){
Toast.makeText(MainActivity.this, "显示图片错误", 0).show();
}
};
};
原理:
1.子线程 利用handler 发送一条消息 消息被放在主线程
的消息队列里面
2.主线程里面有一个looper消息的轮询器
3.如果轮询器发现了新的消息,则调用handleMessage的
方法 处理消息
获取网页内容:
xml文件:
<EditText
android:id="@+id/et_path"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="请输入网址"/>
<Button
android:onClick="click"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="查看"/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:id="@+id/tv_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</ScrollView>
源文件中:
//定义一个消息处理器
private Handler handler = new Handler(){
public void handleMessage(android.os.Messaage msg){
switch(msg.what){
case ERROR:
Toast.makeText(MainActivity.this, "获取数据失败", 0).show();
break;
case SHOW_TEXT:
String text = (String)msg.obj;
tv_content.setText(result);
break;
}
};
};
public void click(View view){
final String path = et_path.getText().toString().trim();
if(TextUtils.isEmpty(path)){
Toast.makeText(this,"路径不能为空", 0).show();
}else{
new Thread(){
public void run(){
try{
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setRequestProperty("User-Agent","XXX");
conn.setRequestProperty("Accept-Language", "zh-cn");
int code = conn.getResponseCode();
if(code == 200){
InputStream is = conn.getInputStream();
String result = StreamTools.readInputStream(is);
//tv_content.setText(result);
Message msg = new Message();
msg.what = SHOW_TEXT;
msg.obj = result;
handler.sendMessage(msg);
}else{
Message msg = new Message();
msg.what= ERROR;
handler.sendMessage(msg);
}
}catch(Exception e){
e.printStackTrace();
Message msg = new Message();
msg.what= ERROR;
handler.sendMessage(msg);
}
};
}.start();
}
}
定义一个类用于输入流转换成文本
publc class StreamTools{
//把输入流的内容转化成字符串
public static String readInputStream(InputStream is){
try{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len = 0;
byte[] buffer = new byte(1024);
while((len = is.read(buffer)) != -1){
baos.write(buffer, 0, len);
}
is.close();
baos.close();//关不关都一样
byte[] result = baos.toByteArray();
return new String(result);
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
不同的浏览器有不同的编码,所以为了能获取到的中文字体不变成乱码,可将代码设置如下:
public static String readInputStream(InputStream is){
try{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len = 0;
byte[] buffer = new byte(1024);
while((len = is.read(buffer)) != -1){
baos.write(buffer, 0, len);
}
is.close();
baos.close();//关不关都一样
byte[] result = baos.toByteArray();
//试着解析 result 里面的字符串
String temp = new String(result);
if(temp.contains("utf-8")){
return temp;
}else if(temp.contains("gb2312")){
return new String(result, "gb2312");
}
return temp;//默认操作
}catch(Exception e){
e.printStackTrace();
return "获取失败";
}
}