SharedPreferenceListener中的CalledFromWrongThreadException

时间:2012-01-18 09:52:56

标签: android sharedpreferences

我有一个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。

感谢您的帮助!

2 个答案:

答案 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仍然会响应。