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);
}
我到食堂里吃饭,师傅尽职地在窗口打菜,这就是两个线程,然后我点了一份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();
}
}
}