Android SharedReferenceListener中的CalledFromErrorThreadException

Android SharedReferenceListener中的CalledFromErrorThreadException,android,sharedpreferences,Android,Sharedpreferences,我有一个IntentService,它会更新如下首选项: SharedPreferences.Editor editor = userPrefs.edit(); editor.putInt("COUNT", intCount); editor.commit(); 在我的主要活动中,我正在监听偏好更改并更新文本视图 userPrefsListener = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override p

我有一个IntentService,它会更新如下首选项:

SharedPreferences.Editor editor = userPrefs.edit();
editor.putInt("COUNT", intCount);
editor.commit();
在我的主要活动中,我正在监听偏好更改并更新文本视图

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);
对于Android2.3,一切正常,但对于2.2,每次触发OnSharedListener时,都会调用FromErrorThreadException


谢谢你的帮助

运行
onSharedPreferenceChanged()
回调的线程不是2.2设备中的主UI线程,该设备提供了从错误线程异常调用
(因此违反了仅从UI线程调用UI toolkit的第二条规则)。让代码在UI线程上运行的一种简单方法是使用。只需将代码主体包装在一个新的
可运行的

activity.runOnUiThread(new Runnable() {
    public void run() {
        // Code which updates UI controls goes here.
    }
});

可以找到关于2.2和2.3之间的更改的简短讨论以及发生更改的原因的代码片段。

运行
onSharedPreferenceChanged()
回调的线程不是2.2设备中的主UI线程,该设备提供了
调用FromErrorThreadException
(因此违反了仅从UI线程调用UI toolkit的第二条规则)。获取要在UI线程上运行的代码的简单方法是使用。只需将代码体包装在新的
可运行的

activity.runOnUiThread(new Runnable() {
    public void run() {
        // Code which updates UI controls goes here.
    }
});

可以找到关于2.2和2.3之间的更改的简短讨论,以及发生更改的原因的代码片段。

之所以提出从错误线程异常调用
,是因为不应该从
IntentService
调用
OnChangeListener

不过,您可以做的是发送一个广播(实际上您也可以包括该值)

如果您仅使用
SharedReference
进行通信,您可以完全替换它(我建议这样做,因为SharedReference会浪费写入周期)

您可以使用如下代码发送广播:

/**
 * 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();
}

您也应该考虑使用<代码>汉德勒<代码> s,所以您在OnCuxEistInter调用中的方法是由MIUI线程运行的。 例如:

Handler mHandler = new Handler();
Runnable myCode = new Runnable(){
     @Override
     protected void onRun() {
          yourCode();
          }
     };
mHandler.run(myCode);

这还具有使用
runDelayed()运行代码delayed的优点
,因此您不必使用
睡眠
,UI仍将响应。

引发
调用FromErrorThreadException
的原因是
OnChangeListener
不应该从
IntentService
调用

不过,您可以做的是发送一个广播(实际上您也可以包括该值)

如果您仅使用
SharedReference
进行通信,您可以完全替换它(我建议这样做,因为SharedReference会浪费写入周期)

您可以使用如下代码发送广播:

/**
 * 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();
}

您也应该考虑使用<代码>汉德勒<代码> s,所以您在OnCuxEistInter调用中的方法是由MIUI线程运行的。 例如:

Handler mHandler = new Handler();
Runnable myCode = new Runnable(){
     @Override
     protected void onRun() {
          yourCode();
          }
     };
mHandler.run(myCode);

这还具有使用
runDelayed()
运行代码延迟的优点,因此您不必使用
sleep
,UI仍将响应。

此回调将在主线程上运行。
,因此可以尝试打印线程名
thread.currentThread().getName()
,如果不是主线程,则可能是原因。
此回调将在主线程上运行。
,因此可以尝试打印线程名
thread.currentThread().getName()
,如果不是主线程,则可能是原因。