解决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());
}