Task and the back stack
Android应用程序由多个activities组成,系统将这些activities按照tasks归类。每一个task把一系列activities表示为一个stack,当用户离开时,activities被放到stack中,当用户浏览回来时,activities被推送出来。这个被叫做back stack。当用户打开一个与当前的activity没有联系的一个新的activity时,新的task就会被创建。每一个task有自己的back stack。
所有ui事件都在主线程,或者叫ui线程中触发。你点击的每一个按钮通过主线程分发并触发一个事件。因此,使用work threads来处理长时间运行的操作就变得很重要。但是,更新UI就变得不是线程安全。如果你试图通过一个work threads更新UI,会导致异常。android 提供了很多解决这个问题的API:
The Activity.runOnUiThread method
The View.post, View.postDelayed, and View.postInvalidate methods
The AsyncTask class
Message handlers
对于同一个activity在back stack中出现多次是有可能。当同一个activity可以从不同的地方被启动的时候,就会发生这种情况。你需要小心这种情形,因为你很容易消耗大量的资源,存储相同的activity。对用户来说,这也是很郁闷的事情,因为他们需要重复的按Back键来退出你的App。
处理配置更改
Android app经常碰到的一个情况是处理设备配置的改变。什么是设备配置改变呢,最基本的一个就是旋转手机时方向的改变。 这个会导致手机从横屏转为竖屏。这个改变导致你当前的activity销毁后重新创建。 此时,如何保存你app的输入数据和状态呢?
你应该在onPause方法中保存数据。但是,这个应该只在用户觉得数据重要的时候才做。在这种情况下,你要保存的数据仅仅与当前存在的activity实例有关,为了实现这个,你可以通过onSaveInstanceState方法来实现。与onPause()方法不同,onSaveInstanceState并不总是被调用,它只有在activity要被销毁并且很可能被重建时才调用。你应该使用onSaveInstanceState来重新创建activity的状态。 这个的典型应用就是保存list中当前的位置,当方向发生变化时,你仍可以保持当前的位置。
避免ANRS
一个android应用在自己的进程运行,在一个单独的线程中运行。为了保证app的响应,android限制了函数的时间。如果某个函数超过时间限制,Application Not Responding对话框就会出现,询问要等待还是强制退出。
StrictMode
Android2.3引入了一个新的开发工具,叫做StrictMode。这个工具会检测在主线程中进行的磁盘或者网络操作,并对开发者发出警告。
StrictMode并不能检测到主线程中出现的所有磁盘和网络操作。尤其,在jni中出现的就不会被检测到。
在当前线程中声明StrictMode的方法:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll() //检测磁盘和网络操作。
.penaltyLog() //打印警告日志。
.penaltyDialog()//显示警告对话框。
.build());
检测所有线程的方法:
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDeath()
.build());
后台Task
handlers and message queues
在后台运行线程是一个防止阻塞UI线程的好方法,但是,当task完成后,你通常需要更新UI。为了实现这个,你可以使用Handler class。Handlers在handleMessage方法中处理消息。
通常,一个Handler实例与创建它的线程绑定(通常是主线程),给UI线程绑定一个handler提供了一个异步更新UI的灵活方法。但是,你也可以在一个单独的线程中运行handler,通过提供一个可选择的Looper实例。 A looper用来为一个线程管理消息循环。使用looper,你可以发送消息,任何一个线程实例都可以让他们执行。
Looper类创建和管理一个叫MessageQueue对象,这个对象控制线程所有的消息。UI线程本身已经有了一个message Queue和looper供你使用。
Activity.runOnUIThread也经常被用到。
AsyncTask
通过继承AsyncTask类,你可以创建一个简单的线程来实现后台的task,并将结果发布到UI线程。
下面是它的简单用法:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
while (true) {
// Do some work
publishProgress((int) ((i / (float) count) * 100));
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog(“Result is “ + result);
}
}