zoukankan      html  css  js  c++  java
  • 第10讲- UI线程阻塞及其优化

    第10讲UI线程阻塞及其优化

    1UI 阻塞demo

    (首先在activity_main.xml中放置两个button,分别命名为button1,button2)

    //首先设置一个button1用来进行动画演示

    Button button1=(Button) findViewById(R.id.button1);

    //位移方向移动的动画

    TranslateAnimation animation=new TranslateAnimation(100,150, 50, 100);

    animation.setDuration(2000);                 //设置持续的时间,单位为微秒

    animation.setRepeatCount(10);             //设置重复的次数

    button1.setAnimation(animation);

    //设置一个button2进行耗时操作sleep

    Button button2=(Button) findViewById(R.id.button2);

    button2.setOnClickListener(new OnClickListener(){

    public void onClick(View v) {

    try {

    Thread.sleep(5000);                                    //设置线程耗时操作,单位ms

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    });

    点击button2之后,button1的移动发生卡死,发生UI线程阻塞。

    当一个应用程序启动之后,Android系统会为这个应用程序创建一个主线程。这个线程非常重要,它负责渲染视图,分发事件到响应监听器并执行,对界面进行轮询监听。因此,一般也叫做“UI线程”。

    Android系统不会给应用程序的多个元素组件,建立多个线程来执行。一个视图(activity)中的多个view组件运行在同一个UI线程当中。因此多个view组件的监听器的执行可能对相互影响(即是UI线程阻塞

    2UI阻塞解决方案:创建一个新线程

    Button button2 = (Button)findViewById(R.id.button2);

    button2.setOnClickListener(new OnClickListener(){

    public void onClick(View v) {

    new Thread(newRunnable() {                 //创建一个新线程

    public void run() {

    try {

    Thread.sleep(5000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }).start();

    }

    });

    将耗时操作放在一个新的线程里面进行操作,利用new Thread().start()打开新的线程。

    此时因为没有更改view,所以不会报错。但是一旦我们在UI线程外修改了view组件的属性,则会报错。

    安卓官方规定的两个规则

    There are two simple rules to Android’ssingle thread model:

    Do not block the UI thread. 不要阻塞UI线程

    Do not access the Android UI toolkit from outside of the UIthread. 不要再UI线程之外的其他线程中,对视图当中的组件进行设置

    违反rule2会报异常:Only the original thread that created aview hierarchy can touch its views.

    3、在其他的线程中修改UI线程中的组件

    方法aview.post

    将需要进行view组件修改的程序部分放在v.post(new Runnable() { }中的run()方法进行即可。

    Buttonbutton2 = (Button) findViewById(R.id.button2);

    button2.setOnClickListener(newOnClickListener() {

    publicvoid onClick(final View v) {

    newThread(newRunnable() {

    publicvoid run() {

    try {

    Thread.sleep(5000);      //设置线程耗时操作,单位ms。在新线程中进行耗时操作

    } catch (InterruptedException e){

    e.printStackTrace();

    }

    } .

    }).start();

    intsum=10;                         //假定通过耗时操作计算处理的得到的一个值

    v.post(newRunnable() {

    public void run() {

    TextView textView=(TextView) v;         //在post中进行view修改操作

    textView.setText(""+10);

    }

    });

    }

    });

    post原理:通过view.post在任务队列中添加一个任务Runnable对象,UI thread在轮询过程中会检查任务队列中是否有任务,有则执行(如下图所示)。此时任务队列中的修改view组件的操作是在UI线程中执行的,则不违反上面的rule2.

    方案a:post方法,可读性差,维护性差。

    原理是在新线程中进行耗时操作,在post中进行view修改操作。

     

      

    方法bAsyncTask (异步任务)

    AsyncTask允许你在你的用户接口上执行异步工作。他在工作者线程中执行阻塞操作,然后将结果发布给 UI线程,不需要你自己处理线程或者 handler。

    为了使用他,你需要继承 AsyncTask并且实现他的 doInBackground()回调方法,他在一个后台线程池中运行。为了更新你的 UI,你需要实现 onPostExecute()方法,他传递来自 doInBackgroud()的结果且在 UI线程中运行。所以你可以安全的更新你的 UI。你可以在 UI线程通过 execute()来运行你的任务。

    privateButton button2 = null;

    protected voidonCreate(Bundle savedInstanceState) {

                       super.onCreate(savedInstanceState);

                       setContentView(R.layout.activity_main);

                      

                       //为button1添加一个动画操作

                       Buttonbutton1 = (Button) findViewById(R.id.button1);

                       //位移方向移动的动画

                       TranslateAnimationanimation = new TranslateAnimation(0,150,0,0);

                       animation.setRepeatCount(30);     //设置重复的次数

                       animation.setDuration(2000);                  //设置持续的时间,单位为微秒

                       button1.setAnimation(animation);

                      

                       button2= (Button) findViewById(R.id.button2);

                       button2.setOnClickListener(newOnClickListener() {

                                publicvoid onClick(final View v){

                                         newDownloadImageTask().execute();

                                }

                               

                       });

             }

             privateclass DownloadImageTask extends AsyncTask<String, Void,Integer> {

                 protected IntegerdoInBackground(String... urls) {

                          try{

                                    Thread.sleep(5000);

                          }catch (InterruptedException e) {

                                    e.printStackTrace();

                          }

                          intsum=10;    

                          returnsum;

                 }

                 protected voidonPostExecute(Integer sum) {

                     button2.setText(""+sum);

                 }

             }

  • 相关阅读:
    runtime iOS 运行时机制
    iOS 文件操作
    responseCode 状态吗查询
    iOS常用宏定义
    Block里用self造成循环引用
    iOS Block全面分析
    OC与Swift混编
    iOS打包app发给测试人员测试
    Swift UITextField
    sqilite学习
  • 原文地址:https://www.cnblogs.com/anyuan9/p/6171610.html
Copyright © 2011-2022 走看看