android菜鸟笔记之UI线程阻塞

来源:互联网 发布:有哪些育儿软件 编辑:程序博客网 时间:2024/05/21 19:46

最近在学习Android,有些还是需要记录下来,方便以后查询

首先

当一个应用程序启动之后,android系统会为这个应用程序创建一个主线程。这个线程非常重要,它负责渲染视图,分发事件到响 应监听器并执行, 对界面进行轮询的监听。因此,一般也叫做“UI”线程。android系统不会给应用程序的多个元素组件,建立多个线程来执行。一个视图(activity)中的多个view组件运行在同一个UI线程当中。因此,多个view组件的监听器的执行可能会相互影响。


例如:当在UI线程当中执行耗时操作,比如访问网络,访问数据库等。则会导致UI线程阻塞。当UI线程阻塞,则屏幕会出现卡死情况。这样用户体验非常差。当线程阻塞超过5秒以后,android系统有可能进行干预,弹出对话框询问是否关闭应用程序。


新建一个android project Application,


打开activity_main.xml,添加button1与button2


在MainActivity.java的onCreate中添加如下代码

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//创建动画按钮Button btn1 = (Button)findViewById(R.id.button1);TranslateAnimation translateAnimation = new TranslateAnimation(0, 150, 0, 0);translateAnimation.setRepeatCount(30);//运行次数translateAnimation.setDuration(2000);//设置越少运动速度越快btn1.setAnimation(translateAnimation);Button btn2 = (Button)findViewById(R.id.button2);btn2.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubtry {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});}
启动运行,当我们点击Button2后,等待片刻后尝试再点击会出现以下


点击OK将退出程序


Android提供了两个解决方案给我们

android的UI规则

there are simply two rules to Android's single thread model;
Do not block the UI thread
不要阻塞UI线程
Do not access the Android UI toolkit from outside the UI thread
不要在UI线程之外的其他线程中,对视图当中的组件进行设置
//经典异常:
Only the original thread that created a view hierarchy can touch its views.
只有创建view的那个线程才能对其进行修改

解决方案1:post


调整onCreate代码如下:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//创建动画按钮Button btn1 = (Button)findViewById(R.id.button1);TranslateAnimation translateAnimation = new TranslateAnimation(0, 150, 0, 0);translateAnimation.setRepeatCount(30);//运行次数translateAnimation.setDuration(2000);//设置越少运动速度越快btn1.setAnimation(translateAnimation);Button btn2 = (Button)findViewById(R.id.button2);btn2.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(final View v) {// TODO Auto-generated method stubnew Thread(new Runnable(){@Overridepublic void run() {System.out.println("线程开始");// TODO Auto-generated method stubtry {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}int i = 20;v.post(new Runnable(){@Overridepublic void run() {System.out.println("post线程开始");// TODO Auto-generated method stubTextView tView = (TextView)v;tView.setText("" + 100);}});System.out.println("线程结束");}}).start();}});}

在日志中看到它把修改Button2的放到了主控制之后执行,但其实Post操作还是在主线程中的,并不是新建一个线程进行操作。

而且Sleep(5000)变成了只针对Button2执行。之前是对全局进行操作。

如图:其实View.Post方式,类似于生产者与消费者的模式。每次UI线程都会在任务队列中查找一次操作,同时View.Post在里面放入自己的操作。


以上代码相当复杂,可读性差,所以官方提供了另一个方法来处理这种问题。

解决方案2:AsyncTask

官方提供了以下片段:

private class DownloadImageTask extends AsyncTask<string void="" bitmap="">{/*the system calls this to perform work in a workerdelivers it the parameters given to AsyncTask.execute()*/protected Bitmap doInBackground(String... urls){return loadImageFromNetwork(urls[0]);}/*The system calls this to perform work in the UI thread and delivers* the result from doInBackground()*/protected void onFostExecute(Bitmap result){mImageView.setImageBitmap(result);}}</string>

由于要写一个内部类所以需要定义全局变量

private Button btn2 = null;

修改代码如下

private Button btn2 = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//创建动画按钮Button btn1 = (Button)findViewById(R.id.button1);TranslateAnimation translateAnimation = new TranslateAnimation(0, 150, 0, 0);translateAnimation.setRepeatCount(30);//运行次数translateAnimation.setDuration(2000);//设置越少运动速度越快btn1.setAnimation(translateAnimation);btn2 = (Button)findViewById(R.id.button2);btn2.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(final View v) {// TODO Auto-generated method stubnew ChangeButtonText().execute();}});}private class ChangeButtonText extends AsyncTask<String, Void, Integer>{protected Integer doInBackground(String... urls){try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}int i = 100;return i;}protected void onFostExecute(Integer result){btn2.setText("" + result);}}
最终结果:

0 0
原创粉丝点击