programing

SharedPreferences.onSharedPreferenceChangeListener가 일관되게 호출되지 않음

megabox 2023. 9. 16. 08:53
반응형

SharedPreferences.onSharedPreferenceChangeListener가 일관되게 호출되지 않음

이와 같이 기본 설정 변경 청취자를 등록합니다. (에서)onCreate() 활동의 :동주동: ) :

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

prefs.registerOnSharedPreferenceChangeListener(
   new SharedPreferences.OnSharedPreferenceChangeListener() {
       public void onSharedPreferenceChanged(
         SharedPreferences prefs, String key) {

         System.out.println(key);
       }
});

문제는 듣는 사람이 항상 불리지 않는다는 것입니다.처음 몇 번은 기본 설정이 변경된 후 앱을 제거하고 다시 설치할 때까지 더 이상 호출되지 않습니다.애플리케이션을 다시 시작해도 해결되지 않는 것 같습니다.

같은 문제를 보고하는 메일링 리스트 스레드를 찾았지만 아무도 그에게 대답하지 않았습니다.내가 뭘 잘못하고 있는 거지?

이것은 교활한 것입니다.공유 기본 설정은 청취자를 약한 해시 맵에 유지합니다.즉, 익명의 내부 클래스는 현재 범위를 벗어나는 즉시 쓰레기 수거 대상이 되므로 청취자로 사용할 수 없습니다.처음에는 작동하지만 결국 쓰레기를 수집하고 WickHashMap에서 제거한 후 작동을 중지합니다.

클래스의 필드에서 리스너에 대한 참조를 유지하면 클래스 인스턴스가 파괴되지 않는 한 문제가 없습니다.

즉, 다음 대신:

prefs.registerOnSharedPreferenceChangeListener(
  new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // Implementation
  }
});

다음 작업을 수행합니다.

// Use instance field for listener
// It will not be gc'd as long as this instance is kept referenced
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // Implementation
  }
};

prefs.registerOnSharedPreferenceChangeListener(listener);

onDestroy 메서드에서 등록을 취소하면 문제가 해결되므로 필드에서 청취자를 저장해야 하므로 문제가 발생하지 않습니다.문제를 해결하는 분야에서 청취자를 구하는 것이지, Destroy에서 등록을 취소하는 것이 아닙니다.

업데이트: Android 문서가 이 동작에 대한 경고업데이트되었습니다.그래서 홀수 행동은 여전합니다.하지만 지금은 문서화되어 있습니다.

이 승인된 답변은 괜찮습니다. 저는 활동이 재개될 때마다 새로운 인스턴스를 생성하고 있기 때문입니다.

그래서 활동 내에서 청취자에 대한 언급을 유지하는 것은 어떨까요?

OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener(){
      public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
         // your stuff
      }
};

그리고 당신의 이력서와 일시정지에

@Override     
public void onResume() {
    super.onResume();          
    getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);     
}

@Override     
public void onPause() {         
    super.onPause();          
    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);

}

이것은 우리가 하드 레퍼런스를 유지하고 있다는 것을 제외하고는 당신이 하고 있는 것과 매우 유사할 것입니다.

은 이 를 .SharedPreferenceChangeListeneronResume라고 합니다.@사무엘은 만드는 것으로 해결합니다.SharedPreferenceListener액티비티 클래스의 멤버하지만 구글이 이 코드랩에서 사용하는 세 번째 그리고 더 간단한 해결책이 있습니다.활동 클래스에서 다음을 구현하도록 합니다.OnSharedPreferenceChangeListener override스의및의및eonSharedPreferenceChanged로동를동를e로n서geyat,yfeSharedPreferenceListener.

public class MainActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {

    }

    @Override
    protected void onStart() {
        super.onStart();
        PreferenceManager.getDefaultSharedPreferences(this)
                .registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        PreferenceManager.getDefaultSharedPreferences(this)
                .unregisterOnSharedPreferenceChangeListener(this);
    }
}

이 페이지가 주제에 대한 가장 상세한 페이지이기 때문에 제 50ct를 추가하고 싶습니다.

OnShared Preference ChangeListener가 호출되지 않는 문제가 있었습니다.기본 활동을 시작할 때 다음과 같은 방법으로 공유 환경설정을 검색합니다.

prefs = PreferenceManager.getDefaultSharedPreferences(this);

내 기본 설정 활동 코드는 짧고 기본 설정을 표시하는 것 외에는 아무것도 수행하지 않습니다.

public class Preferences extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // load the XML preferences file
        addPreferencesFromResource(R.xml.preferences);
    }
}

메뉴 버튼을 누를 때마다 메인 액티비티에서 Preference Activity를 만듭니다.

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    //start Preference activity to show preferences on screen
    startActivity(new Intent(this, Preferences.class));
    //hook into sharedPreferences. THIS NEEDS TO BE DONE AFTER CREATING THE ACTIVITY!!!
    prefs.registerOnSharedPreferenceChangeListener(this);
    return false;
}

OnSharedPreferenceChangeListener 등록은 이 경우 PreferenceActivity를 생성한 후에 수행해야 합니다. 그렇지 않으면 기본Activity의 Handler가 호출되지 않습니다!!!제가 깨닫는 데는 시간이 좀 걸렸습니다...

Cotlin Code for register SharedPreferenceChangeListener는 저장된 키에서 변경이 발생할 때를 감지합니다.

  PreferenceManager.getDefaultSharedPreferences(this)
        .registerOnSharedPreferenceChangeListener { sharedPreferences, key ->
            if(key=="language") {
                //Do Something 
            }
        }

이 코드를 Start()에 넣거나 다른 곳에 넣을 수 있습니다.*사용해야 함을 고려하여

 if(key=="YourKey")

또는 "/Do Something" 블록 내의 코드가 공유 기본 설정의 다른 키에서 발생하는 모든 변경 사항에 대해 잘못 실행됩니다.

그래서, 이것이 누군가에게 정말 도움이 될지는 모르겠지만, 그것은 제 문제를 해결해주었습니다.비록 내가 그것을 실행했었지만,OnSharedPreferenceChangeListener승낙된 대답대로하지만 저는 듣는 사람이 불려가는 것에 대해 일관성이 없었습니다.

시간이 지나면 안드로이드가 쓰레기 수거를 위해 보내는 것으로 알고 싶어서 왔습니다.그래서 제 코드를 확인했습니다.유감스럽게도, 나는 듣는 사람을 세계적으로 선언하지 않았고, 대신에 세계 내부에서 선언했습니다.onCreateView입니다. 그리고 그것은 안드로이드 스튜디오에서 청취자를 지역 변수로 전환하라는 말을 들었기 때문입니다.

청취자가 WickHashMap에 보관되어 있는 것은 이해가 됩니다.왜냐하면 대부분의 경우 개발자들은 이렇게 코드를 작성하는 것을 선호하기 때문입니다.

PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(
    new OnSharedPreferenceChangeListener() {
    @Override
    public void onSharedPreferenceChanged(
        SharedPreferences sharedPreferences, String key) {
        Log.i(LOGTAG, "testOnSharedPreferenceChangedWrong key =" + key);
    }
});

나쁘지 않은 것 같습니다.그러나 OnShared Preference ChangeListeners의 컨테이너가 WeakHashMap이 아니라면 매우 좋지 않을 것입니다.위 코드가 액티비티에 작성된 경우.엔클로저 인스턴스의 참조를 암시적으로 유지하는 정적(익명)이 아닌 내부 클래스를 사용하고 있기 때문입니다.메모리 누수의 원인이 됩니다.

또한 리스너를 필드로 유지하는 경우 처음에 registerOnSharedPreferenceChangeListener를 사용하고 마지막에 unregisterOnSharedPreferenceChangeListener를 호출할 수 있습니다.그러나 범위를 벗어난 메서드에서는 로컬 변수에 액세스할 수 없습니다.따라서 등록할 기회는 있지만 청취자 등록을 취소할 기회는 없습니다.따라서 WickHashMap을 사용하면 문제가 해결됩니다.이것이 제가 추천하는 방법입니다.

리스너 인스턴스를 정적 필드로 만들면 정적이 아닌 내부 클래스로 인한 메모리 누수를 방지할 수 있습니다.하지만 청취자가 여러 명일 수도 있기 때문에 인스턴스(instance)와 관련이 있어야 합니다.이렇게 하면 onShared Preferences Changed 콜백 처리 비용이 절감됩니다.

첫번째 앱으로 공유된 Word readible data를 보면서 우리는

교체하다

getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);

와 함께

getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);

두 번째 앱에서 업데이트된 값을 얻을 수 있습니다.

하지만 아직도 작동이 안 돼요

언급URL : https://stackoverflow.com/questions/2542938/sharedpreferences-onsharedpreferencechangelistener-not-being-called-consistently

반응형