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