Handler、缓存图片

ANR的解决和 Handler 的使用

在 Android 4.0 以上会有特殊效果。 Message 的 obj 和 what 属性的使用。

  • ANR 异常

    • 当应用长时间没有响应用户操作,会导致异常。一般是 5-6 秒
    • 当连接网络耗时很长的时候,在2.3 上会报异常:Application is not responding
    • 在 4.0 上运行会报异常:android.os.NetworkOnMainThreadException
    • 在主线程做耗时操作会阻塞主线程,导致应用无法响应用户的最新操作
    • 如果要做耗时操作,必须在子线程处理
  • Handler 的使用

    • 在子线程更新界面会报异常: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    • 将子线程的数据送到主线程才能更新界面
    • —子线程不能操作ui,(可以调用,但不能修改ui)

    创建 Handler 对象

    // 8.1 创建 Handler 对象
    Handler handler = new Handler(){
        // 当子线程调用 sendMessage 发送消息,会在主线程执行 handleMessage
        public void handleMessage(android.os.Message msg) {
            // 8.3 在主线程接收数据
            String content = (String) msg.obj;
            tv_content.setText(content);
        };
    };

    在子线程发送消息

    // 8.2 在子线程使用 Handler 对象发送消息到主线程
    Message msg = new Message();
    msg.obj = content; // 把源码字符串,封装到消息对象里
    handler.sendMessage(msg);// 发松消息到主线程
  • 网络操作里的线程操作

    • 不能在主线程发起网络操作,必须开启子线程
    • 子线程不允许更新 UI,需要使用 Handler 将数据发送到主线程
    • 主线程接收到 消息之后,获取数据并且更新界面

了解 Handler-Looper 运行机制的底层原理

要知道主线程是什么?可以打印线程名

  • Message里what 的使用
    // 8.1 创建 Handler 对象
    Handler handler = new Handler(){
        // 当子线程调用 sendMessage 发送消息,会在主线程执行 handleMessage
        public void handleMessage(android.os.Message msg) {
            int what = msg.what;
            // 根据what类型,分别做不同的处理
            switch (what) {
            case 0:
                // 成功
                // 8.3 在主线程接收数据
                String content = (String) msg.obj;
                tv_content.setText(content);
                break;
            case 1:
                // 异常
                // 发生了异常,弹出吐司提示用户
                Toast.makeText(MainActivity.this, "服务器忙", 0).show();
                break;

            default:
                break;
            }
        };
    };

图片查看器

obtainMessage 可以节约内存

  • BitmapFactory

    • 可以从 文件、输入流、项目资源 生成bitmap 对象
    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
    iv_content.setImageBitmap(bitmap);

runOnUiThread 方法的使用和图片的缓存处理

  • runOnUiThread 和 Handler的区别
    • runOnUiThread 只能在 Activity 里面使用
    • Handler 可以在所有的类使用
  • 缓存图片的代码
    // 获取用户的输入信息,连接服务器,获取图片,展示到界面上
    public void click(View view) {
        // System.out.println("MainActivity.click,");
        // 网络操作会耗时很长,必须要放在子线程处理
        new Thread(){
            public void run() {
                File cacheFile = new File(getCacheDir(), "test.png");
                System.out.println("MainActivity.run,cacheFile="+cacheFile.getAbsolutePath());
                if (cacheFile.exists()) {
                    System.out.println("MainActivity.run,存在缓存文件");
                    // 存在缓存文件,直接加载,不去联网
                    final Bitmap bitmap = BitmapFactory.decodeFile(cacheFile.getAbsolutePath());
                    runOnUiThread(new Runnable() {
                        public void run() {
                            iv_content.setImageBitmap(bitmap);
                        }
                    });
                    return;
                }

                // 获取用户输入的地址
                String urlStr = et_url.getText().toString();

                // 连接服务器,获取网页源码
                try {
                    // 1. 创建 URL 地址对象
                    URL url = new URL(urlStr);
                    // 2. 获取网络操作的工具类
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    // 3. 设置请求参数
                    connection.setRequestMethod("GET");// GET 必须大写
                    connection.setConnectTimeout(5000);
                    // 4. 发起请求,获取服务器的响应码
                    int code = connection.getResponseCode();
//                  System.out.println("code="+code);

                    // 5. 判断请求码的数值。 200 连接成功 404 网页不存在 206 部分成功
                    if (code == 200) {
                        // 线程休眠。模拟时间延迟
//                      SystemClock.sleep(10000);

                        // 6. 连接成功.获取服务器的输入流
                        InputStream inputStream = connection.getInputStream();

                        // 将输入流的内容保存到缓存文件
                        int len = 0;
                        byte[] buffer = new byte[1024];
                        FileOutputStream fos = new FileOutputStream(cacheFile);
                        while ((len = inputStream.read(buffer))!= -1) {
                            fos.write(buffer, 0, len);
                        }
                        inputStream.close();
                        fos.close();

                        // 7. 从输入流读取数据,获取获取图片
                        final Bitmap bitmap = BitmapFactory.decodeFile(cacheFile.getAbsolutePath());

                        // 8. 将获取的字符串显示到界面上
                        runOnUiThread(new Runnable() {
                            public void run() {
                                iv_content.setImageBitmap(bitmap);
                            }
                        });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        }.start();
    }

使用Handler和计时器处理延时效果

public class MainActivity extends Activity {

    private Timer timer;
    private TimerTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 延时2秒后打开下一个界面
        /*new Handler().postDelayed(new Runnable() {
            public void run() {
                System.out.println("跳转到下一个界面啦!");
            }
        }, 2000);*/

        // 定时器实现延时效果
        timer = new Timer();
        task = new TimerTask() {

            @Override
            public void run() {
                // 当定时到了之后,会执行这个方法
                System.out.println("跳转到下一个界面啦!lalalalalala");
            }
        };

        timer.schedule(task , 2000 , 1000);

    }

    @Override
    /** 当界面被销毁时调用 */
    protected void onDestroy() {
        super.onDestroy();
        // 取消定时器
        timer.cancel();
        task.cancel();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值