我需要使用runOnUiThread
更新一些UI并在UI线程内部进行更新
现在,UI的数据来自另一个线程,在此处由data
表示。
如何将数据传递给Runnable,以便它们可用于更新UI? Android似乎不允许直接使用数据。是否有一种优雅的方式来做到这一点?
public void OnNewSensorData(Data data) {
runOnUiThread(new Runnable() {
public void run() {
//use data
}
});
}
我的解决方案是在runnable中创建一个fioeld private Data sensordata
,并为其分配数据。这仅适用于原始Data data
是最终的。
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
private Data sensordata = data;
public void run() {
//use sensordata which is equal to data
}
});
}
答案 0 :(得分:36)
您发现的问题是
Java中的内部类捕获(“关闭”)其中的词法范围 他们是定义的。但它们只捕获声明为“最终”的变量。
如果这很清楚,那么这里有一个很好的讨论细节: Cannot refer to a non-final variable inside an inner class defined in a different method
但你的解决方案看起来不错。此外,如果data
是最终版,您可以将代码简化为:
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
public void run() {
// use data here
data.doSomething();
}
});
}
答案 1 :(得分:21)
如果您想避免使用中间最终变量(如Dan S所述),您可以使用其他方法实现Runnable来设置数据:
public class MyRunnable implements Runnable {
private Data data;
public void setData(Data _data) {
this.data = _data;
}
public void run() {
// do whatever you want with data
}
}
然后你可以这样调用这个方法:
public void OnNewSensorData(Data data) {
MyRunnable runnable = new MyRunnable();
runnable.setData(data);
runOnUiThread(runnable);
}
您还可以使MyRunnable的构造函数将Data实例作为参数:
public class MyRunnable implements Runnable {
private Data data;
public MyRunnable(Data _data) {
this.data = _data;
}
public void run() {
...
}
}
然后只说runOnUiThread(new MyRunnable(data));
答案 2 :(得分:5)
我有一个类似的问题,我想把信息传递给线程。为了用android系统解决它,我修改了corsiKa的答案:Runnable with a parameter?
您可以在方法中声明一个类,并传递参数,如下所示:
void Foo(String str) {
class OneShotTask implements Runnable {
String str;
OneShotTask(String s) { str = s; }
public void run() {
someFunc(str);
}
}
runOnUiThread(new OneShotTask(str));
}
答案 3 :(得分:1)
每当您的计划有新的Data
想要展示时,您就需要更新。您在此处列出的第二个代码是实现此目标的标准方法。如果您继续在线程中更新Data
,可能会有一些捕获。如果是这种情况,请考虑阻止线程,直到UI完成更新或将数据复制到另一个Data
对象。
内部发生的事情是JVM正在复制对Data
对象的引用,以便匿名类运行。存储在里面的Data
仍然可以更改。如果您的方法需要对Data
进行其他更改,请使用另一个变量(对象引用),例如:final Data finalData = data;
。您也可以删除行private Data sensordata = data;
并直接在run方法中使用数据。
它可能看起来不优雅,但这是Java将对象变量传递给匿名类的方式。 Java语言版本7中有更新的语法,但Android与Java语言版本5和6兼容。
答案 4 :(得分:1)
以下是调用服务回调以更新UI状态字符串(TextView textStatus)的典型情况。该服务可能是线程化的。
该示例结合检查是否需要线程重定向和实际重定向:
// service callbacks
public void service_StatusTextChanged(final String s) {
if( isOnUiThread() ) {
textStatus.setText(s);
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
textStatus.setText(s);
}
});
}
}
static public boolean isOnUiThread() {
return Thread.currentThread() == Looper.getMainLooper().getThread();
}
答案 5 :(得分:0)
public static Activity globalContext = null;
CommonSetting.globalContext = this;// put this in MainACtivity.onCreate()
public void createToastShort(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(CommonSetting.globalContext, message, Toast.LENGTH_SHORT).show();
}
});
}