CalledFromWrongThreadException в SharedPreferenceListener - PullRequest
1 голос
/ 18 января 2012

У меня есть 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 я получаю CalledFromWrongThreadException каждый раз, когда срабатывает OnSharedListener.

Спасибо за вашу помощь!

Ответы [ 2 ]

3 голосов
/ 23 января 2012

Поток, выполняющий обратный вызов onSharedPreferenceChanged(), не является основным потоком пользовательского интерфейса в устройстве 2.2, что дает вам CalledFromWrongThreadException (поэтому нарушается второе из правил доступа к потоку пользовательского интерфейса Android только для вызова инструментария пользовательского интерфейса из потока пользовательского интерфейса). Простой способ заставить код работать в потоке пользовательского интерфейса - использовать Activity.runOnUiThread () . Это можно сделать, просто обернув тело вашего кода в новый Runnable:

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

Краткое обсуждение изменения между 2.2 и 2.3 и фрагментов кода о том, почему это произошло, можно найти здесь .

1 голос
/ 23 января 2012

Причина, по которой 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 s, чтобы ваши методы в вызове OnChangeListener выполнялись потоком MainUI.

* * Пример тысяча двадцать-один: * * 1 022
Handler mHandler = new Handler();
Runnable myCode = new Runnable(){
     @Override
     protected void onRun() {
          yourCode();
          }
     };
mHandler.run(myCode);

Это также дает преимущество запуска кода с задержкой на runDelayed(), поэтому вам не нужно использовать sleep, и ваш пользовательский интерфейс будет по-прежнему отвечать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...