当前位置:首页 » 安卓系统 » android线程更新ui

android线程更新ui

发布时间: 2022-07-08 22:33:06

① android通过Handler使子线程更新UI

在Android项目中经常有碰到这样的问题,在子线程中完成耗时操作之后要更新UI,下面就自己经历的一些项目总结一下更新的方法。

一. 引言

首先来看一下android中消息机制:

专业术语:

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

二. 方法

1. 用Handler

(1)主线程中定义Handler:

java代码:

[java]view plain

HandlermHandler=newHandler(){

@Override

publicvoidhandleMessage(Messagemsg){

super.handleMessage(msg);

switch(msg.what){

case0:

<spanstyle="color:#009900;">//完成主界面更新,拿到数据</span>

Stringdata=(String)msg.obj;

updateWeather();

textView.setText(data);

break;

default:

break;

}

}

};

(2)子线程发消息,通知Handler完成UI更新:

java代码:

privatevoipdateWeather(){

newThread(newRunnable(){

@Override

publicvoidrun(){

<spanstyle="color:#009900;">//耗时操作,完成之后发送消息给Handler,完成UI更新;</span>

mHandler.sendEmptyMessage(0);

<spanstyle="color:#33cc00;">//需要数据传递,用下面方法;</span>

Messagemsg=newMessage();

msg.obj="数据";<spanstyle="color:#33cc00;">//可以是基本类型,可以是对象,可以是List、map等;</span>

mHandler.sendMessage(msg);

}

}).start();

}

注意:Handler对象必须定义在主线程中,如果是多个类直接互相调用,就不是很方便,需要传递content对象或通过接口调用。

2.用Activity对象的runOnUiThread方法更新

在子线程中通过runOnUiThread()方法更新UI:

java代码:

newThread(){

publicvoidrun(){

<spanstyle="color:#009900;">//这儿是耗时操作,完成之后更新UI;</span>

runOnUiThread(newRunnable(){

@Override

publicvoidrun(){

<spanstyle="color:#009900;">//更新UI</span>

imageView.setImageBitmap(bitmap);

}

});

}

}.start();

如果在非上下文类中,可以通过传递上下文实现调用:

java代码:

Activityactivity=(Activity)imageView.getContext();

activity.runOnUiThread(newRunnable(){

@Override

publicvoidrun(){

imageView.setImageBitmap(bitmap);

}

});

注意:这种方法使用比较灵活,但如果Thread定义在其他地方,需要传递Activity对象。


3.
View.post(Runnable r)

java代码:

imageView.post(newRunnable(){

@Override

publicvoidrun(){

imageView.setImageBitmap(bitmap);

}

});

这种方法更简单,但需要传递要更新的View过去。

总结:UI的更新必须在主线程中完成,所以不管上述那种方法,都是将更新UI的消息发送到了主线程的消息对象,让主线程做处理。

② Android更新Ui的几种方法和见解

  1. 利用Looper更新UI界面

  2. 2.AsyncTask利用线程任务异步更新UI界面

  3. 3.利用Runnable更新UI界面

③ android怎么更新UI

首先,android的UI刷新是在主线程(UI线程)中完成的。四大组件中,activity和service运行在主线程中。现在总结自己在项目中常用到的UI刷新方式。
第一,利用子线程发消息刷新UI。
子线程负责处理UI需要的数据,然后发消息到主线程来刷新UI。代码结构如下:
new Thread(new Runnable() {

@Override
public void run() {
Person person=new Person();
person.setName(mName.getText().toString().trim());
person.setPhone(mPhone.getText().toString().trim());
Log.i("person",person.toString());
DatabaseInfoFactory.getPersonDao(mContext).addPerson(person);
Looper.prepare();
Message msg=Message.obtain();
msg.what=0x123456;
handler.sendMessage(msg);
Looper.loop();

}
}).start();
主线程中:
private Handler mHandler=new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.what==0x123456||msg.what==0x123){
fillData();
setListener();
}

}
};
第二,利用异步任务更新UI。代码结构如下:
new AsyncTask<void,void,void>() {

@Override
protected void onPostExecute(Void result) {

if(mAdapter==null){
mAdapter=new LeaveInfoAdapter();
//设置数据适配器
mLVleaveInfos.setAdapter(mAdapter);
Log.i("测试", "异步任务显示后台获得数据库数据");
}
else {
mAdapter.notifyDataSetChanged();

}

super.onPostExecute(result);
}

@Override
protected Void doInBackground(Void... params) {
//获得要显示的数据
mleaveInfos=mLeaveInfosDao.findAll();
if (mleaveInfos==null) {
Toast.makeText(HomeActivity.this,"请假数据不存在或是已经清除!", 500).show();

}

Log.i("测试", "异步任务后台获得数据库数据"+mleaveInfos.size());

return null;
}
}.execute();</void,void,void>
第三,利用配置文件+activity的生命周期方法刷新UI。

④ Android 在子线程中更新UI的几种方法示例

请您慢慢看:

直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,如下错误:android.view.ViewRoot$: Only the original thread that created a view hierarchy can touch its views.翻译过来就是:只有创建这个控件的线程才能去更新该控件的内容。

所有的UI线程要去负责View的创建并且维护它,例如更新冒个TextView的显示,都必须在主线程中去做,我们不能直接在UI线程中去创建子线程,要利用消息机制:handler,如下就是handler的简单工作原理图:

既然android给我们提供了Handler机制来解决这样的问题,请看如下代码:

public class HandlerTestActivity extends Activity { private TextView tv; private static final int UPDATE = 0; private Handler handler = new Handler() { @Overridepublic void handleMessage(Message msg) { // TODO 接收消息并且去更新UI线程上的控件内容if (msg.what == UPDATE) { // Bundle b = msg.getData();// tv.setText(b.getString("num")); tv.setText(String.valueOf(msg.obj)); } super.handleMessage(msg); } }; /** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tv = (TextView) findViewById(R.id.tv); new Thread() { @Overridepublic void run() { // TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值try { for (int i = 0; i < 100; i++) { Thread.sleep(500); Message msg = new Message(); msg.what = UPDATE; // Bundle b = new Bundle();// b.putString("num", "更新后的值:" + i);// msg.setData(b); msg.obj = "更新后的值:" + i; handler.sendMessage(msg); } } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }}

我们就通过Handler机制来处理了子线程去更新UI线程控件问题,Andrid开发中要经常用到这种机制。

⑤ android中如何实现UI的实时更新

1、在主线程中启动一个子线程

首先,我们需要在主线程中启动一个子线程,这个比较简单,直接在MainActivity的onCreate()方法中调用如下方法即可:

newThread(mRunnable).start();

2、在子线程中发送Message给Handler

在创建子线程时,我们使用了Runnable接口对象mRunnable。这里,只需要实现Runnable接口,并重写该接口的run()方法,在run()方法中实现每1秒发送一条Message给Handler即可。具体实现方法如下:

/*
*Function:实现run()方法,每1秒发送一条Message给Handler
*/
privateRunnablemRunnable=newRunnable(){
publicvoidrun(){
while(true){
try{
Thread.sleep(1000);
mHandler.sendMessage(mHandler.obtainMessage());
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
};

3、Handler接收Message通知

最后,我们创建一个Handler对象,用来接收Message通知。在收到Message通知后,完成刷新UI的操作即可。具体实现方法如下:

/*
*Function:实现handleMessage()方法,用于接收Message,刷新UI
*/
privateHandlermHandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
refreshUI();
}
};

4、刷新UI

由以上的代码可以看出,刷新UI的操作,我们是放在refreshUI()方法中来完成的。refreshUI()方法的实现也很简单,调用HttpUtils工具类中的getInputStream()方法,获得图1所示Web工程的页面内容输入流,再将该输入流转化为字符串,放入TextView控件中进行显示即可。具体实现方法如下:

/*
*Function:刷新UI
*/
privatevoidrefreshUI(){
try{
InputStreaminputStream=HttpUtils.getInputStream();
StringresultData=HttpUtils.getResultData(inputStream);
mTextView.setText(resultData);
}catch(IOExceptione){
e.printStackTrace();
}
}

⑥ 如何在android一条单独线程,更新ui

方法有两种:
通过继承Thread类,重写Run方法来实现
通过继承接口Runnable实现多线程
主要接受子线程发送的数据, 并用此数据配合主线程更新UI.

Handler的主要作用:主要用于异步消息的处理

Handler的运行过程:
当(子线程)发出一个消息之后,首先进入一个(主线程的)消息队列,发送消息的函数即刻返回,而在主线程中的Handler逐个的在消息队列中将消息取出,然后对消息进行处理。这样就实现了跨线程的UI更新(实际上还是在主线程中完成的)。
这种机制通常用来处理相对耗时比较长的操作,如访问网络比较耗时的操作,读取文大文件,比较耗时的操作处理等。

在大白话一点的介绍它的运行过程:
启动应用时Android开启一个主线程
(也就是UI线程) , 如果此时需要一个耗时的操作,例如:
联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象(这也就是你在主线程中直接访问网络时会提示你异常的原因,如我们上篇文章所述Android主线程不能访问网络异常解决办法)。

⑦ android 怎么刷新UI组件

首先,android的UI刷新是在主线程(UI线程)中完成的。四大组件中,activity和service运行在主线程中。现在总结自己在项目中常用到的UI刷新方式。
第一,利用子线程发消息刷新UI。
子线程负责处理UI需要的数据,然后发消息到主线程来刷新UI。代码结构如下:
new Thread(new Runnable() {

@Override
public void run() {
Person person=new Person();
person.setName(mName.getText().toString().trim());
person.setPhone(mPhone.getText().toString().trim());
Log.i("person",person.toString());
DatabaseInfoFactory.getPersonDao(mContext).addPerson(person);
Looper.prepare();
Message msg=Message.obtain();
msg.what=0x123456;
handler.sendMessage(msg);
Looper.loop();

}
}).start();
主线程中:
private Handler mHandler=new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.what==0x123456||msg.what==0x123){
fillData();
setListener();
}

}
};
第二,利用异步任务更新UI。代码结构如下:
new AsyncTask<void,void,void>() {

@Override
protected void onPostExecute(Void result) {

if(mAdapter==null){
mAdapter=new LeaveInfoAdapter();
//设置数据适配器
mLVleaveInfos.setAdapter(mAdapter);
Log.i("测试", "异步任务显示后台获得数据库数据");
}
else {
mAdapter.notifyDataSetChanged();

}

super.onPostExecute(result);
}

@Override
protected Void doInBackground(Void... params) {
//获得要显示的数据
mleaveInfos=mLeaveInfosDao.findAll();
if (mleaveInfos==null) {
Toast.makeText(HomeActivity.this,"请假数据不存在或是已经清除!", 500).show();

}

Log.i("测试", "异步任务后台获得数据库数据"+mleaveInfos.size());

return null;
}
}.execute();</void,void,void>
第三,利用配置文件+activity的生命周期方法刷新UI。

⑧ android怎么样在子线程实例化的handler去更新UI

之前用过android-async-http,虽然没认真看过源码,但也有简单的浏览过,心里一直有个疑问,因为android-async-http也是采用hanlder机制来执行回调的,也就是说handler是它实例化的,可我们知道handler的一个重要作用是将一个任务切换到handler所在的线程去执行的,我的疑问就是:如果我们在子线程调用android-async-http的网络请求,这时候如果handler是在子线程被实例化的呢(当然我没认真研究过源码,也不知道它是怎么实现),还能更新UI吗?
我们都正常以为handler在哪个线程实例化的,我们通过handler就可以把任务切换到该任务去执行,我们看如下代码:

private void initd() {

new Thread(new Runnable() {

@Override

public
void run() {

Looper.prepare();

Handler handler = new
Handler() {

@Override

public void handleMessage(Message msg) {

Toast.makeText(MainActivity.this, "测试子线程弹出toast",
Toast.LENGTH_LONG).show();

((TextView)findViewById(R.id.main_tv_text)).setText("测试子线程");

}

};

Looper.loop();

handler.sendEmptyMessage(0);

}

}).start();

}

经过我的测试上面这段方法是无法更新UI的,因为handler是在子线程实例化的,并非在UI线程,也证实了我们的想法。

如果我的疑问存在(我没尝试过在子线程使用android-async-http,不知道什么情况,这里只是做个假设),那么它使怎么实现的呢。

最近看了android开发艺术探索,特意去研究了一下android的消息机制,才弄明白了Handler的工作原理,其实起关键作用的是Looper并不是handler,我们先来看下Looper的构造方法:

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

Looper会把所在的当前的线程保存起来,而handler的工作需要Looper,于是我尝试了一下如下代码:

private void init() {

new Thread(new Runnable() {

@Override

public
void run() {

Handler handler = new
Handler(Looper.getMainLooper()) {

@Override

public void handleMessage(Message msg) {

Toast.makeText(MainActivity.this, "测试子线程弹出toast",
Toast.LENGTH_LONG).show();

((TextView)findViewById(R.id.main_tv_text)).setText("测试子线程");

}

};

handler.sendEmptyMessage(0);

}

}).start();

}

handler实例化的时候,我传入的是UI线程的Looper,确实是可以更新UI。

总结:

1、handler执行任务不是在它实例化所在的线程决定的,而是关键在于Looper。

2、我们可以在子线程实例化handler并且可以用它来更新UI了。

热点内容
C语言预编译的例子 发布:2025-04-07 07:12:27 浏览:756
软件加密破解 发布:2025-04-07 07:04:34 浏览:835
乌合之众中央编译出版社百度网盘 发布:2025-04-07 06:53:12 浏览:805
美颜算法磨皮 发布:2025-04-07 06:38:37 浏览:4
手机视频源码下载 发布:2025-04-07 06:34:21 浏览:739
安卓手机投屏到电视上怎么切换 发布:2025-04-07 06:22:02 浏览:379
支票密码多少位 发布:2025-04-07 06:16:09 浏览:282
php观察 发布:2025-04-07 06:16:06 浏览:868
累不存储 发布:2025-04-07 06:09:42 浏览:364
pythonos删除文件 发布:2025-04-07 05:59:02 浏览:366