解决Android主线程内不能同步访问网络资源的问题

1. 问题描述: 多线程的异步

  • 在Android4.0之后的版本,为防止应用的ANR(aplication Not Response)异常,主线程中不再允许访问网络,否则将抛出NetworkOnMainThreadException的错误(如下图所示)。故需要创建子线程实现网络访问、图片资源加载。
    在这里插入图片描述
  • 但若是使用子线程,则需面临线程间的通讯问题,并且可能会出现主线程(如用户界面渲染)已经执行完毕、但子线程请求的网络资源(如图片)还未到达的情形(异步),导致页面异常显示。

2. 解决方法: thread.start()->thread.join()

  • 在Java中,join()的实现基于wait()方法,主线程调用子线程构成的同步代码块,随之主线程持有了同步锁并进入wait()状态;当子线程执行完毕时,jvm调用notifyAll方法去唤醒在等待状态的主线程,执行后续的代码片段,实现了线程间的顺序(同步)执行;
  • 执行子线程的join()方法后,主线程必须等待子线程执行完毕才能进入下一步操作;

子线程代码片段:

// 网络图片请求子线程
final Thread thread1 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println("子线程执行中");
                for (int i = 0; i < imageNames.size(); i++) {
                    String imageName = imageNames.getString(i);
                    // 通过url获得图片数据
                    Bitmap bitmap = getBitmapFromServer(imageName);
                    bitmaps.add(bitmap);
                }
                //子线程等待, 后唤醒lockObject锁
                System.out.println("子线程执行完毕");
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("子线程:"+ e.toString());
            }
        }
    });

主线程代码片段:

	// 在主线程中需要使用网络资源的代码片断前插入
	// 阻塞主线程,使子线程按照“同步”的方式执行
	try {
	    System.out.println("线程开始");
	    thread1.start();    // 线程启动
	    thread1.join();     // 线程加入执行队列,主线程被阻塞,等待子线程执行完毕
	} catch (Exception e) {
	    e.printStackTrace();
	    System.out.println(e.toString());
	}
posted @ 2020-07-17 00:00  litchi99  阅读(206)  评论(0编辑  收藏  举报