UI线程与非UI线程 android开发

来源:互联网 发布:材料化学考研方向知乎 编辑:程序博客网 时间:2024/06/03 22:41

1、UI线程和非UI线程介绍


进过了快一个多星期的学习把一直卡在这个地方,最后找了朋友a_mean协助,算是解决了这个难题

问题一:什么是线程?

O-0:这个问题也是纠结了两天,由于在上操作系统的课也提到一些,这里具体的定义网上比我讲的详细,我就按自己的意思说一下,线程就是进程执行后的东西,两者可以相互转换。一个进程可以有多个线程组成。举个例子:我在的浏览器上可以同时打开多个网页,当我在对某一个网页进行浏览的时候,这是就先当于一个运行的进程,那就是线程,那其他的线程呢,等在等待中。。。就是进程。以上只是我个人的理解可能有错,请即使指出。

问题二:android里面的UI线程和非UI线程是什么?

以下内容是引用:

   在一个Android 程序开始运行的时候,会单独启动一个Process。默认的情况下,所有这个程序中的Activity或者Service(Service和 Activity只是Android提供的Components中的两种,除此之外还有Content Provider和Broadcast Receiver)都会跑在这个Process。

        一个Android 程序默认情况下也只有一个Process,但一个Process下却可以有许多个Thread。
   
       在这么多Thread当中,有一个Thread,我们称之为UI Thread。UI Thread在Android程序运行的时候就被创建,是一个Process当中的主线程Main Thread,主要是负责控制UI界面的显示、更新和控件交互。在Android程序创建之初,一个Process呈现的是单线程模型,所有的任务都在一 个线程中运行。因此,我们认为,UI Thread所执行的每一个函数,所花费的时间都应该是越短越好。而其他比较费时的工作(访问网络,下载数据,查询数据库等),都应该交由子线程去执行, 以免阻塞主线程。

说明了这两点后来看看代码吧-----再次感谢好友a_mean的指导

 

public class HandlertestActivity extends Activity {

    /** Called when the activity is first created. */

private Button ok;

private LinearLayout L;

    private MyHandler myHandler;  

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    L=(LinearLayout) findViewById(R.id.sime);

     

        try {

          new Thread(new Mythread()).start();

      } catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

       

 

    }

    class Mythread implements Runnable

    {

 

   

@Override

public void run()

{

 L.setBackgroundColor(Color.RED);

}

}
这段代码就是在我初始化的时候能够将界面设置为红色的。
这个地方说个囧事,我开始以为那个R.layout.main可以直接对我背景的布局进行操作,结果不行要去LinearLayout控件那里加ID咯,默认的话是没有的。。。
     new Thread(new Mythread()).start();这句就是新建一个线程改变我的背景我红色的开始,start。
上面的这段代码中UI线程就是我的OnCreate里面这些代码程序吧(有错就说)Mythread就是我的非UI线程
android里面有个定理就是不能在非UI线程中改变UI线程,好的最为纠结的地方就来了,我明明是在非UI中修改UI的啊?经过 了两天的调试和a_mean的帮助明白了。
这里a_mean给我说了个经典的例子,让我豁然开朗是这样说的   原文地址      http://blog.csdn.net/a_mean/article/details/6972364

我到食堂里吃饭,师傅尽职地在窗口打菜,这就是两个线程,然后我点了一份TextView,里面装着Modify。最后我拿到这份TextView,回到座位上把它给吃了。

这个例子一切正常,所以什么异常都没有,然后第二天我又去了这个食堂。这天不知是我去得早了,还是这个师傅动作有些慢了。

我到食堂里吃饭,师傅一边XXX一边在炒菜,我惊呆了。然后他把炒好的TextView端上来,我抛出一个恶心反胃的异常,逃走了再也没有再来过这家食堂。

这两个例子,一个报错了一个没有,其实就在于我到食堂的时间,师傅是否已经做好了菜,就像上面的例子,UI线程和MyThead线程几乎是同时执行,

但后者的工作量太少了,更改了TextView上面的字就完成了,这里UI线程把这个UI展示出来,一切都很正常。但要是我们让MyThead在run的时候先睡眠几秒钟呢?

或者是弄一个按钮,点击按钮后MyThead才开始?这样都是在UI线程加载完成后才通过非UI线程对它进行修改的,一定会报错!

这就是多线程编程,有时候你运行若干次,结果正确,并不表明你的逻辑就是对的。我们一定要遵循代码的规范,保持清晰的思维。

看到红色那句话没有,我想你已经懂了。就是上面那个道理,例子说的话,就是我去点菜了,但是不知道什么原因,菜迟迟不来,我等急了气走了。

因此就有了下面的这种写法

 

import android.app.Activity;

import android.graphics.Color;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.LinearLayout;

 

public class HandlertestActivity extends Activity {

    /** Called when the activity is first created. */

private Button ok;

private LinearLayout L;

    private MyHandler myHandler;  

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

    L=(LinearLayout) findViewById(R.id.sime);

    myHandler=new MyHandler();

        new Thread(new Mythread()).start();

 

    }

    class Mythread implements Runnable

    {

 

   

@Override

public void run()

{

 

 Message msg=new Message(); 

 myHandler.sendMessage(msg); 

}

 

   

    }

    

 

    class MyHandler extends Handler

    {

    @Override  

        public void handleMessage(Message msg) {  

   

           L.setBackgroundColor(Color.RED);

        

        }  

     

    }  

}

这个Myhandler是什么角色呢?

myThread是服务生,在UI线程(食堂)中有一个myHandler(厨师),我告诉服务生我点的菜,服务生就开始run,然后send一个Message给厨师myHandler,
myHandler收到消息开始做菜的动作,最后UI线程展示这道做好的菜。



2、在非UI线程中更新UI界面的两种方法

Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。 

invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。 一个Android 程序默认情况下也只有一个进程,但一个进程下却可以有许多个线程。

在这么多线程当中,把主要是负责控制UI界面的显示、更新和控件交互的线程称为UI线程,由于onCreate()方法是由UI线程执行的,所以也可以把UI线程理解为主线程。其余的线程可以理解为工作者线程。

invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通知UI线程进行界面更新。

而postInvalidate()在工作者线程中被调用

 

 

利用invalidate()刷新界面

  实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。 
// 在onCreate()中开启线程

new Thread(new GameThread()).start();、

// 实例化一个handler

Handler myHandler = new Handler() {
// 接收到消息后处理
public void handleMessage(Message msg) {
switch (msg.what) {
case Activity01.REFRESH:
mGameView.invalidate(); // 刷新界面
break;
}

super.handleMessage(msg);
}
};

class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
Message message = new Message();
message.what = Activity01.REFRESH;
// 发送消息
Activity01.this.myHandler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}


使用postInvalidate()刷新界面

    使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。 

class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}

// 使用postInvalidate可以直接在线程中更新界面
mGameView.postInvalidate();
}
}
}





原创粉丝点击