Android核心基础-6.Android 耗时操作
2015-07-26 22:43
531 查看
1.什么是ANR
在应用程序的主线程中执行一段耗时的代码, 就有可能出现ANR异常.耗时的代码未执行结束时, 界面会卡住, 用户对界面进行了操作, 10秒之后耗时代码如果还未结束, 就会出现ANR异常
我们的布局文件中有个TextView和一个按钮Button
<TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="30sp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="go" android:text="GO" />
当点击Button按钮时触发go()函数,我们看到函数中执行了一个耗时操作,此时将出现界面卡死现象。
public void go(View v) { for (int i = 1; ; i++) { System.out.println(i); SystemClock.sleep(1000); } }
2.怎么避免ANR
主线程中不要执行耗时的代码如果一定要做耗时的事情, 开启新线程, 在新线程中执行
我们将耗时操作放置在一个线程中,那么界面就不会被卡死。
public void go(View v) { new Thread() { public void run() { for (int i = 1; ; i++) { System.out.println(i); SystemClock.sleep(1000); } } }.start(); }
3.UI Thread
安卓手机中主线程负责刷新界面, 以及处理用户的操作应用程序的界面都是由主线程创建的
界面的修改也只能在主线程中执行
4.Handler
有的时候我们需要执行一些耗时的代码, 会开启新线程, 这时又需要更新界面, 必须在主线程中操作, 那么就需要使用Handler来进行线程之间的通信4.1 sendMessage():
新线程向主线程发送一个包含数据的消息, 主线程获取消息中的数据在主线程中创建Handler子类对象, 重写handleMessage()方法
新线程中可以使用Handler的引用调用sendMessage()方法, 发送一个Message对象
只要执行了sendMessage()方法, 那么主线程会自动执行handleMessage()方法, 收到Message对象
4.2 post():
新线程向主线程发送一段代码, 主线程直接执行在主线程中创建Handler对象
新线程中可以使用Handler调用post()方法发送一个Runnable对象
主线程会自动执行Runable的run()
通过Handler发送Message通知主线程更新界面
public class SendMessageActivity extends Activity { private TextView tv; private Handler handler = new Handler(){ public void handleMessage(Message msg) { // 该方法在sendMessage()方法之后执行, 形参就是发送过来的Message对象 tv.setText(msg.obj + ""); // 主线程更新界面 } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); } public void go(View v) { new Thread() { public void run() { for (int i = 1; ; i++) { // Message msg = new Message(); // 创建消息对象 Message msg = handler.obtainMessage(); // 从消息池中获取一个Message(比直接new效率要高) msg.obj = i; // 把数据放在消息对象中 handler.sendMessage(msg); // 在新线程中发送消息对象, 主线程会自动执行handleMessage()方法 System.out.println(i); SystemClock.sleep(1000); } } }.start(); } }
课外知识:Message.obtain()和Handler.obtain()原理都一样,都是去消息池获取一个新的message对象。
但是Message的池全局性更高,两个线程同时使用到同一个的概率高;而Handler的范围相对要小点,指定了某一个Handler的Message对象。
直接通过post发送一段可执行代码更新界面
public class PostActivity extends Activity { private TextView tv; private Handler handler = new Handler(); private int i; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); } public void go(View v) { System.out.println("go: " + Thread.currentThread().getName()); new Thread() { public void run() { System.out.println("run: " + Thread.currentThread().getName()); for (i = 1; ; i += 2) { handler.post(new Runnable(){ // 在新线程中使用Handler向主线程发送一段代码, 主线程自动执行run()方法 public void run() { System.out.println("Runnable: " + Thread.currentThread().getName()); tv.setText(i + ""); } }); System.out.println(i); SystemClock.sleep(1000); } } }.start(); } }
通过打印出来的log:
我们看到go: main, run: Thread-143, Runnable: main
表明post中的代码在主线程中执行的。
示例源代码->百度网盘
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件