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 "获取失败";

        }

    }

posted @ 2015-10-25 16:36  飞牛冲天  阅读(514)  评论(0编辑  收藏  举报