我有一个IntentService来更新这样的偏好:
SharedPreferences.Editor editor = userPrefs.edit();
editor.putInt("COUNT", intCount);
editor.commit();
在我的主要活动中,我正在侦听偏好更改并更新TextView
userPrefsListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals("COUNT")) {
final TextView txvCounter = (TextView) findViewById(R.id.TXV_COUNTER);
if(txvCounter != null) {
SharedPreferences userPrefs = getSharedPreferences("USER_SCORE", 0);
int intCount = userPrefs.getInt("COUNT", 0);
txvFishcounter.setText(String.format("%03d",intCount));
}
}
}
};
userPrefs.registerOnSharedPreferenceChangeListener(userPrefsListener);
对于Android 2.3,一切正常,但对于2.2,每次触发OnSharedListener时,我都会收到CalledFromWrongThreadException。
感谢您的帮助!
答案 0 :(得分:3)
运行onSharedPreferenceChanged()
回调的线程不是2.2设备中的主要UI线程,它为您提供CalledFromWrongThreadException
(因此违反了仅调用UI工具包的Android UI thread access rules中的第二个UI线程)。获取代码以在UI线程上运行的直接方法是使用Activity.runOnUiThread()。这可以通过将代码正文包装在新的Runnable
:
activity.runOnUiThread(new Runnable() {
public void run() {
// Code which updates UI controls goes here.
}
});
可以找到2.2和2.3之间的变化以及发生原因的代码片段的简短讨论here。
答案 1 :(得分:1)
引发CalledFromWrongThreadException
的原因是因为OnChangeListener
不应该从IntentService
调用。
你可以做的是发送一个广播(你也可以实际包含这个值)。
如果您仅使用SharedPreference
进行通信,则可以完全替换它(我建议这样做,因为SharedPreferences正在浪费写入周期)。
您可以使用这样的代码发送广播:
/**
* Send an Intent with the Broadcast, a permission and a Bundle
*
* @param context
* A context to use
* @param broadcast
* String to use, eg. "de.bulling.smstalk.ENABLE"
* @param permission
* Permission needed for receiving
* @param bundle
* Extras to attach
*/
public static void send_broadcast(Context context, String broadcast, String permission, Bundle bundle) {
//SettingsClass.log_me(tag, "Sending broadcast " + broadcast);
Intent i = new Intent();
i.setAction(broadcast);
if (bundle != null) {
i.putExtras(bundle);
}
if (permission != null) {
context.sendBroadcast(i, permission);
} else {
context.sendBroadcast(i);
}
}
您还应该包含自定义权限,因此其他应用无法获得广播,但不一定需要。
要接收广播,请在您的活动中注册接收者,例如
private final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
doSomething();
}
};
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
IntentFilter filter = new IntentFilter();
filter.addAction(YOURBROADCAST);
registerReceiver(receiver, filter);
[...]
}
@Override
public void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
}
此外,您应该考虑使用Handler
,因此OnChangeListener调用中的方法由MainUI线程运行。
示例:
Handler mHandler = new Handler();
Runnable myCode = new Runnable(){
@Override
protected void onRun() {
yourCode();
}
};
mHandler.run(myCode);
这也有使用runDelayed()
延迟运行代码的优势,因此您不必使用sleep
,并且您的UI仍然会响应。