10 UI线程阻塞及其优化
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10 UI线程阻塞及其优化相关的知识,希望对你有一定的参考价值。
1、button1移动30次的小动画:
Ui_thread01Activity.java:
public class Ui_thread01Activity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //为button1添加一个动画 Button button1=(Button)findViewById(R.id.button1); //类似jQuery中的animate方法 TranslateAnimation animation=new TranslateAnimation(0,150,0,0);//在x轴上移动150 animation.setRepeatCount(30);//重复30次 animation.setDuration(2000);//设置动画经历时间 button1.setAnimation(animation); } }
运行结果:button1不停在移动,移动30次
2、button1移动30次时,button2也有相应事件的小动画:
Ui_thread01Activity.java:
public class Ui_thread01Activity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //为button1添加一个动画 Button button1=(Button)findViewById(R.id.button1); //类似jQuery中的animate方法 TranslateAnimation animation=new TranslateAnimation(0,150,0,0);//在x轴上移动150 animation.setRepeatCount(30);//重复30次 animation.setDuration(2000);//设置动画经历时间 button1.setAnimation(animation); //为button2添加相应事件 Button button2=(Button)findViewById(R.id.button2); button2.setOnClickListener(new OnClickListener(){ public void onClick(View v) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
运行结果:
一开始button一直在做平移运动,当点击button2时,button1就停止运动,过一段时间之后,button1继续运动直到30次结束;
Main thread(UI thread)
当一个应用程序启动之后,android系统会为这个应用程序创建一个主线程。这个线程非常重要,它负责渲染视图,分发事件到响应监听器并执行,对界面进行轮询的监听。因此,一般也叫做“UI线程”。
Android系统不会给应用程序的多个元素组件,建立多个线程来执行。一个视图(activity)中的多个view组件运行在同一个UI线程当中。因此,多个view组件的监听器的执行可能会相互影响。
例如:当在ui线程中执行耗时操作,比如访问网络,访问数据库等。则会导致UI线程阻塞。当UI线程阻塞,则屏幕会出现卡死情况。这样用户体验非常差。当线程阻塞超过5秒以后,Android系统有可能进行干预,弹出对话框询问是否关闭应用程序。
例如,当我们把button2的相应事件中时间改为50秒;那么此时系统会自行进行干预:
代码:Thread.sleep(50000);
运行结果:
如何让程序不引起阻塞;解决方案:
1、创建一个新的线程;
代码:
public class Ui_thread01Activity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //为button1添加一个动画 Button button1=(Button)findViewById(R.id.button1); //类似jQuery中的animate方法 TranslateAnimation animation=new TranslateAnimation(0,150,0,0);//在x轴上移动150 animation.setRepeatCount(30);//重复30次 animation.setDuration(2000);//设置动画经历时间 button1.setAnimation(animation); //为button2添加相应事件 Button button2=(Button)findViewById(R.id.button2); button2.setOnClickListener(new OnClickListener(){ public void onClick(View v) { //创建一个新的线程 new Thread(new Runnable(){ public void run() { try { Thread.sleep(50000); }catch (InterruptedException e) { e.printStackTrace(); } } }).start();; } }); } }
运行效果:(当button2点击的时候,不会停止button1的移动)
2、然而会有新的问题发生;
官方规则:
把上面setOnClickListener的代码改成:
会产生问题的代码:
button2.setOnClickListener(new OnClickListener(){ public void onClick(final View v) { //创建一个新的线程 new Thread(new Runnable(){ public void run() { try { Thread.sleep(50000); }catch (InterruptedException e) { e.printStackTrace(); } //执行之后把button2上面的字改成10 int sum=10;//通过耗时操作计算处理一个值 TextView view = (TextView) v; view.setText(""+10); } }).start();; } });
运行结果:
对此问题的解决措施:
1、用解决方案1:view.post:
原理图:
public class Ui_thread01Activity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //为button1添加一个动画 Button button1=(Button)findViewById(R.id.button1); //类似jQuery中的animate方法 TranslateAnimation animation=new TranslateAnimation(0,150,0,0);//在x轴上移动150 animation.setRepeatCount(30);//重复30次 animation.setDuration(2000);//设置动画经历时间 button1.setAnimation(animation); //为button2添加相应事件 Button button2=(Button)findViewById(R.id.button2); button2.setOnClickListener(new OnClickListener(){ public void onClick(final View v) { //创建一个新的线程 new Thread(new Runnable(){ public void run() { Log.i("myinfo", "线程开始执行!!!"); try { Thread.sleep(5000); }catch (InterruptedException e) { e.printStackTrace(); } //执行之后把button2上面的字改成10 int sum=10;//通过耗时操作计算处理一个值 v.post(new Runnable(){ public void run() { Log.i("myinfo", "post开始执行!!!"); TextView view = (TextView) v; view.setText(""+10); } }); Log.i("myinfo", "线程执行结束!!!"); } }).start();; } }); } }
运行结果:点击button2之后,过一段时间,button2会变成10,不会产生阻塞。
LogCat显示情况:
次解决方法的缺点:
可读性差,维护性差;
2、用解决方案2:AsyncTask:(最佳解决方案)
异步:此方法写法与view.post相同,只是将方法进行了封装。
分成后台执行的耗时任务和与UI组件进行交互的任务;
代码:
public class Ui_thread01Activity extends Activity { Button button2=null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //为button1添加一个动画 Button button1=(Button)findViewById(R.id.button1); //类似jQuery中的animate方法 TranslateAnimation animation=new TranslateAnimation(0,150,0,0);//在x轴上移动150 animation.setRepeatCount(30);//重复30次 animation.setDuration(2000);//设置动画经历时间 button1.setAnimation(animation); //为button2添加相应事件 Button button2=(Button)findViewById(R.id.button2); button2.setOnClickListener(new OnClickListener(){ public void onClick(final View v) { //执行,创建Task对象 new DownloadImageTask().execute(); } }); } private class DownloadImageTask extends AsyncTask<String, Void, Integer>{ @Override protected Integer doInBackground(String...urls ) { try{ Thread.sleep(5000); }catch(InterruptedException e){ e.printStackTrace(); } int sum=10; return sum; } @Override protected void onPostExecute(Integer sum) { button2.setText(""+sum); } } }
运行结果:
以上是关于10 UI线程阻塞及其优化的主要内容,如果未能解决你的问题,请参考以下文章
异步代码是不是在 UI 线程或新/不同线程中运行以不阻塞 UI?