通过线程中的处理程序更新主活动中的 UI(Android)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2799180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Update UI in the main activity through handler in a thread (Android)
提问by Hrk
I try to make several connection in a class and update the multiple progressbar in the main screen.
我尝试在一个班级中建立多个连接并更新主屏幕中的多个进度条。
But I've got the following error trying to use thread in android : Code: 05-06 13:13:11.092: ERROR/ConnectionManager(22854): ERROR:Can't create handler inside thread that has not called Looper.prepare()
但是我在尝试在 android 中使用线程时遇到以下错误:代码:05-06 13:13:11.092: ERROR/ConnectionManager(22854): ERROR:Can't create handler inside thread that has not called Looper.prepare( )
Here is a small part of my code in the main Activity
这是我在主 Activity 中的一小部分代码
public class Act_Main extends ListActivity
{
private ConnectionManager cm;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Set up the window layout
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.main);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
}
public void startConnection()
{
//open DB connection
db = new DBAdapter(getApplicationContext());
db.open();
cm = new ConnectionManager(handler, db);
showDialog(DIALOG_PROGRESS_LOGIN);
}
@Override
public void onStart()
{
super.onStart();
startConnection();
}
protected Dialog onCreateDialog(int id)
{
switch (id)
{
case DIALOG_PROGRESS_LOGIN:
progressDialog = new ProgressDialog(Act_Main.this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage("Connecting.\nPlease wait...");
progressThreadLogin = new ProgressThreadLogin();
progressThreadLogin.start();
return progressDialog;
case DIALOG_PROGRESS_NETWORK:
[b]progressDialog = new ProgressDialog(Act_Main.this);[/b]
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage("Loading entire network.\nPlease wait...");
progressThreadNetwork = new ProgressThreadNetwork();
progressThreadNetwork.start();
return progressDialog;
default:
return null;
}
}
// Define the Handler that receives messages from the thread and update the progress
final Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
int total = msg.getData().getInt("total");
int step = msg.getData().getInt("step");
Log.d(TAG, "handleMessage:PROCESSBAR:"+total);
progressDialog.setProgress(total);
if (total >= 100)
{
switch (step)
{
case UPDATE_NETWORK:
dismissDialog(DIALOG_PROGRESS_LOGIN);
showDialog(DIALOG_PROGRESS_NETWORK);
cm.getNetwork();
break;
....
default:
break;
}
}
}
};
private class ProgressThreadLogin extends Thread
{
ProgressThreadLogin() { }
public void run() { cm.login(); }
}
private class ProgressThreadNetwork extends Thread
{
ProgressThreadNetwork() { }
public void run() { cm.getNetwork(); }
}
}
And my connectionManager class:
还有我的 connectionManager 类:
public class ConnectionManager
{
public ConnectionManager(Handler handler, DBAdapter db)
{
this.handler = handler;
this.db = db;
}
public void updateProgressBar(int step, int value)
{
if (value == 0)
total = total+1;
else
total = value ;
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putInt("total", total);
b.putInt("step", step);
msg.setData(b);
handler.handleMessage(msg);
}
public void login()
{
//DO MY LOGIN TASK
updateProgressBar(Act_Main.UPDATE_NETWORK, 100);
}
}
The crash errors occurs on the first line of "case DIALOG_PROGRESS_NETWORK:". My first progressbar is hidden but the second one is not displayed.
崩溃错误发生在“case DIALOG_PROGRESS_NETWORK:”的第一行。我的第一个进度条已隐藏,但第二个进度条未显示。
I think I've done somthing wrong using the threads and handlers but I dont' know why.
我想我在使用线程和处理程序时做错了,但我不知道为什么。
I was first using handler.sendMessage in place of handler.handleMessage but when I had several task in my connectionManager, the progressbar was updated only at the end of all tasks.
我首先使用 handler.sendMessage 代替 handler.handleMessage 但是当我的 connectionManager 中有几个任务时,进度条仅在所有任务结束时更新。
Thank you in advance for your help
预先感谢您的帮助
回答by yanchenko
Make Handler handler
non-final and init it inside onCreate()
.
制作Handler handler
非最终版并将其初始化在onCreate()
.
回答by Gautier Hayoun
Having the Handler final and declaring it in the class definition is perfectly fine. Moreover in your last snippet of code when you initialize your Handler in onCreate, you are actually "shadowing" the handler declared in your class, so not initializing it. I'm quite surprised you didn't had any NullPointerException.
将 Handler 设为 final 并在类定义中声明它是完全没问题的。此外,在您在 onCreate 中初始化处理程序时的最后一段代码中,您实际上是在“隐藏”类中声明的处理程序,因此没有对其进行初始化。我很惊讶你没有任何 NullPointerException。
But in ConnectionManager::updateProgressBar you really need to call sendMessage() because by calling handleMessage() directly, the handler gets called from the thread of ConnectionManager::updateProgressBar (which is probably not the UI thread).
但是在 ConnectionManager::updateProgressBar 中,您确实需要调用 sendMessage() 因为通过直接调用 handleMessage(),处理程序会从 ConnectionManager::updateProgressBar 的线程(可能不是 UI 线程)中调用。
I'm not sure what caused you the problem of having the progress bars updated only once, but it's surely a logic bug somewhere. Try to log at different steps of your app -ie. before sending the message, and while handling it-.
我不确定是什么导致了进度条只更新一次的问题,但这肯定是某个地方的逻辑错误。尝试在应用程序的不同步骤登录 - 即。在发送消息之前,以及在处理消息时——。
回答by Tomislav
Hrk, the shadowing part is when you declare a local variable inside the method which has the same name as the field:
Hrk,阴影部分是当您在方法中声明一个与字段同名的局部变量时:
Handler handler = ...
To use the field, omit the type:
要使用该字段,请省略类型:
handler = ...
Regarding exception, just instantiate ProgressDialog
objects in main thread (say, in onCreate() method) and call one of it's show() methods later.
关于异常,只需ProgressDialog
在主线程中实例化对象(例如,在 onCreate() 方法中)并稍后调用其中一个 show() 方法。