SharedPreferences.onSredredPreferencesChangeListener ধারাবাহিকভাবে ডাকা হচ্ছে না


267

আমি এটির মতো একটি অগ্রাধিকার পরিবর্তন শ্রোতাদের নিবন্ধকরণ করছি ( onCreate()আমার মূল ক্রিয়াকলাপের মধ্যে):

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

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

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

সমস্যাটি হ'ল শ্রোতা সর্বদা ডাকা হয় না। এটি প্রথম কয়েকবার পছন্দ পছন্দ পরিবর্তিত হয় এবং আমি অ্যাপটি আনইনস্টল ও পুনরায় ইনস্টল না করা পর্যন্ত এটি আর কল করা হয় না। অ্যাপ্লিকেশনটি পুনঃসূচনা করার কোনও পরিমাণই এটি ঠিক করছে বলে মনে হচ্ছে না।

আমি একই সমস্যাটির প্রতিবেদন করে একটি মেলিং তালিকা থ্রেড পেয়েছি , কিন্তু সত্যই তাকে উত্তর দেয়নি। আমি কি ভুল করছি?

উত্তর:


612

এটি একটি লুক্কায়িত। SharedPreferences শ্রোতাদের একটি WeakHashMap এ রাখে। এর অর্থ হ'ল আপনি শ্রোতা হিসাবে কোনও বেনামে অভ্যন্তরীণ শ্রেণিটি ব্যবহার করতে পারবেন না কারণ এটি আপনার বর্তমান সুযোগ ছাড়ার সাথে সাথে আবর্জনা সংগ্রহের লক্ষ্য হয়ে উঠবে। এটি প্রথমে কাজ করবে, তবে শেষ পর্যন্ত, আবর্জনা সংগ্রহ করবে, উইকহ্যাশম্যাপ থেকে সরানো হবে এবং কাজ করা বন্ধ করবে।

শ্রেনীর কাছে আপনার শ্রেণীর কোনও ক্ষেত্রে একটি রেফারেন্স রাখুন এবং আপনি ঠিক থাকবেন, তবে আপনার শ্রেণীর উদাহরণটি বিনষ্ট না হয়।

এর পরিবর্তে:

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);

অনডেট্রয়ে পদ্ধতিতে নিবন্ধভুক্তির কারণ সমস্যার সমাধান করে কারণ আপনাকে শ্রোতাদের একটি ক্ষেত্রে সংরক্ষণ করতে হয়েছিল, তাই সমস্যাটি রোধ করে। এটি এমন একটি ক্ষেত্রের শ্রোতাদের সংরক্ষণ যা অনডেট্রয়ে নিবন্ধনবিহীন নয়, সমস্যার সমাধান করে।

আপডেট : অ্যান্ড্রয়েড ডক্স এই আচরণ সম্পর্কে সতর্কতা সহ আপডেট করা হয়েছে । সুতরাং, অডবোল আচরণ অবশেষ। কিন্তু এখন এটি নথিভুক্ত।


20
এটি আমাকে হত্যা করছিল, আমি ভেবেছিলাম আমার মন হারাচ্ছে। এই সমাধান পোস্ট করার জন্য আপনাকে ধন্যবাদ!
ব্র্যাড হেইন

10
এই পোস্টটি বিশাল, অনেক ধন্যবাদ, এটি আমার অসম্ভব ডিবাগিং কয়েক ঘন্টা ব্যয় করতে পারে!
কেভিন গাউডিন

আশ্চর্যজনক, এটি কেবল আমার প্রয়োজন ছিল। ভাল ব্যাখ্যাও!
স্টিলথকপ্টার

এটি ইতিমধ্যে আমাকে বিট করেছে, এবং এই পোস্টটি পড়া না হওয়া পর্যন্ত আমি জানতাম না। ধন্যবাদ! বু, অ্যান্ড্রয়েড!
নেকেবল

5
দুর্দান্ত উত্তর, আপনাকে ধন্যবাদ। অবশ্যই ডক্সে উল্লেখ করা উচিত। কোড.google.com/p/android/issues/detail?id=48589
আন্দ্রে চের্নিহ

16

এই গৃহীত উত্তরটি ঠিক আছে, কারণ আমার জন্য এটি প্রতিবার ক্রিয়াকলাপ শুরু হওয়ার সাথে সাথে নতুন ঘটনা তৈরি করছে

সুতরাং কীভাবে শ্রোতার রেফারেন্সটি ক্রিয়াকলাপের মধ্যে রাখবেন

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

এবং আপনার অনারিউম এবং অনপেজ এ

@Override     
protected void onResume() {
    super.onResume();          
    getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(myPrefListner);     
}



@Override     
protected void onPause() {         
    super.onPause();          
    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(myPrefListner);

}

এটি আপনি যা করছেন তার সাথে খুব মিলে যাবে যদি আমরা একটি কঠোর রেফারেন্স বজায় না থাকি।


কেন আপনি super.onResume()আগে ব্যবহার করেছেন getPreferenceScreen()...?
ইউশা আলেয়াউব

@ ইউশাআলিয়াউব, android.app.supernotcalledexception সম্পর্কে পড়ুন এটি অ্যান্ড্রয়েড বাস্তবায়ন দ্বারা প্রয়োজনীয়।
স্যামুয়েল

আপনি কি বোঝাতে চেয়েছেন? ব্যবহারের super.onResume()প্রয়োজন হয় বা এটি ব্যবহারের আগে getPreferenceScreen()প্রয়োজন কি? কারণ আমি সঠিক জায়গার কথা বলছি। cs.dartmouth.edu/~campbell/cs65/lecture05/lecture05.html
ইউশা আলেয়ুব

আমার মনে আছে এটি এখানে ডেভেলপার.অ্যান্ড্রয়েড / ট্রেনিং / বেসিক্স / সক্রিয়তা- লাইফেসাইকেল / পড়া , কোডটিতে মন্তব্য দেখুন। তবে এটি লেজুতে রাখা যৌক্তিক। তবে এখন পর্যন্ত আমি এতে কোনও সমস্যার মুখোমুখি হইনি।
স্যামুয়েল

অনেক ধন্যবাদ, অন্য যে কোনও জায়গায় আমি অনারুম () এবং অনপজ () পদ্ধতিটি তারা নিবন্ধভুক্ত করেছি thisএবং না listenerপেয়েছি, এর ফলে ত্রুটি হয়েছিল এবং আমি আমার সমস্যা সমাধান করতে পারি। বিটিডব্লিউ এই দুটি পদ্ধতি এখন প্রকাশ্যে, সুরক্ষিত নয়
নিকোলাস

16

যেহেতু আমি এই বিষয়ের জন্য সর্বাধিক বিস্তারিত পৃষ্ঠা হ'ল আমি আমার 50 ক্যার্ট যোগ করতে চাই।

অন্যাশার্ডপ্রিফারেন্সচেনজলিস্টনারকে কল করা হয়নি এমন আমার সমস্যা ছিল। আমার ভাগ করা অগ্রাধিকারগুলি মূল ক্রিয়াকলাপের শুরুতে এই দ্বারা পুনরুদ্ধার করা হয়েছে:

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);
    }
}

প্রতিবার মেনু বোতাম টিপলে আমি মূল ক্রিয়াকলাপ থেকে পছন্দক্রম তৈরি করি:

@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;
}

নোট করুন যে এই ক্ষেত্রে পছন্দসইটি তৈরি করার পরে অন্যাশার্ডপ্রিফেরেন্সচেনজলিস্টনারের নিবন্ধন করা দরকার, অন্যথায় মূল ক্রিয়াকলাপে হ্যান্ডলারটি কল করা হবে না !!! এটা বুঝতে আমার কিছুটা সময় লাগল ...


9

গৃহীত উত্তরটি SharedPreferenceChangeListenerপ্রতিবার তৈরি onResumeহয়। @ সামুয়েল SharedPreferenceListenerক্রিয়াকলাপ শ্রেণীর সদস্য করে এটি সমাধান করে । কিন্তু একটি তৃতীয় এবং একটি আরো সহজবোধ্য সমাধান যে গুগল এছাড়াও ব্যবহার এই codelab । আপনার ক্রিয়াকলাপ শ্রেণিকে OnSharedPreferenceChangeListenerইন্টারফেসটি onSharedPreferenceChangedকার্যকর করুন এবং ক্রিয়াকলাপে ওভাররাইড করুন, কার্যকরভাবে ক্রিয়াকলাপটিকে নিজেই একটি করে তোলেন SharedPreferenceListener

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);
    }
}

1
ঠিক, এটি হওয়া উচিত। ইন্টারফেসটি প্রয়োগ করুন, অনস্টার্টে নিবন্ধন করুন এবং অনস্টপে নিবন্ধন করুন।
জুনেদ

2

ভাগ করে নেওয়া কীতে পরিবর্তন কখন ঘটবে তা সনাক্ত করে SharedPreferencesChangeListener রেজিস্ট্রারের জন্য কোটলিন কোড:

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

আপনি এই কোডটি অন স্টার্ট () বা অন্য কোথাও রাখতে পারেন। * আপনার অবশ্যই ব্যবহার করা উচিত তা বিবেচনা করুন

 if(key=="YourKey")

বা "// কিছু কর" ব্লকের ভিতরে থাকা আপনার কোডগুলি ভাগ করে নেওয়া পছন্দগুলিতে অন্য কোনও কীতে ঘটে যাওয়া প্রতিটি পরিবর্তনের জন্য ভুলভাবে চালানো হবে shared


1

সুতরাং, আমি জানি না এটি সত্যিকার অর্থে কাউকে সহায়তা করবে কিনা, এটি আমার সমস্যার সমাধান করেছে। যদিও আমি গৃহীত উত্তরOnSharedPreferenceChangeListener দ্বারা বর্ণিত হিসাবে বাস্তবায়িত হয়েছিল । তবুও, শ্রোতাদের ডাকা হওয়ার সাথে আমার একটি অসঙ্গতি ছিল।

আমি এখানে এসে বুঝতে পারি যে অ্যান্ড্রয়েড কিছু সময়ের পরে কেবল এটি আবর্জনা সংগ্রহের জন্য প্রেরণ করে। সুতরাং, আমি আমার কোডটি দেখেছি। আমার লজ্জা করার জন্য, আমি শ্রোতা ঘোষিত নি বিশ্বব্যাপী কিন্তু এর পরিবর্তে ভিতরে onCreateView। এবং এ কারণেই আমি অ্যান্ড্রয়েড স্টুডিও শুনেছিলাম শ্রোতাকে একটি স্থানীয় ভেরিয়েবলে রূপান্তর করতে।


0

শ্রোতাদের WeakHashMap- এ রাখা হয়েছে বলে মনে করা যায় ec কারণ বেশিরভাগ সময়, বিকাশকারীরা কোডটি লিখতে পছন্দ করেন।

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

এটি খারাপ নাও লাগতে পারে। তবে যদি অন্যাশার্ডপ্রিফেরেন্স চ্যাঞ্জলিস্টেনারগুলির ধারক ওয়েকহ্যাশম্যাপ না হয় তবে এটি খুব খারাপ হবে above উপরের কোডটি যদি কোনও ক্রিয়াকলাপে লেখা থাকে। যেহেতু আপনি অ স্থির (বেনামে) অভ্যন্তর শ্রেণীর ব্যবহার করছেন যা অন্তর্নিহিত উদাহরণটির রেফারেন্সটি সুস্পষ্টভাবে ধারণ করবে। এর ফলে স্মৃতি ফাঁস হবে।

আরো কি, আপনি একটি ক্ষেত্র যেমন শ্রোতা রাখা থাকে, তাহলে আপনি ব্যবহার করতে পারে registerOnSharedPreferenceChangeListener শুরুতে এবং কল unregisterOnSharedPreferenceChangeListener শেষ। তবে আপনি এর সুযোগের বাইরে কোনও পদ্ধতিতে স্থানীয় ভেরিয়েবল অ্যাক্সেস করতে পারবেন না। সুতরাং আপনার কাছে কেবল নিবন্ধকরণের সুযোগ রয়েছে তবে শ্রোতাদের নিবন্ধন করার কোনও সুযোগ নেই। এভাবে WeakHashMap ব্যবহার করা সমস্যার সমাধান করবে। এইভাবেই আমি প্রস্তাব দিই।

যদি আপনি শ্রোতার উদাহরণটিকে স্থির ক্ষেত্র হিসাবে করেন তবে এটি অ স্থিতিশীল অভ্যন্তর শ্রেণীর দ্বারা সৃষ্ট মেমরি ফাঁস এড়াতে পারে। শ্রোতা যেমন একাধিক হতে পারে, এটি উদাহরণ-সম্পর্কিত হওয়া উচিত। এটি onsredPreferencesChanged কলব্যাক পরিচালনা করার জন্য ব্যয় হ্রাস করবে ।


-3

প্রথম অ্যাপ্লিকেশন দ্বারা ভাগ করা শব্দ পঠনযোগ্য ডেটা পড়ার সময় আমাদের উচিত

প্রতিস্থাপন করা

getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);

সঙ্গে

getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);

দ্বিতীয় অ্যাপ্লিকেশানে দ্বিতীয় অ্যাপ্লিকেশনে আপডেট হওয়া মান পেতে।

কিন্তু এখনও এটি কাজ করে না ...


অ্যান্ড্রয়েড একাধিক প্রক্রিয়া থেকে ভাগ করে নেওয়া পছন্দগুলি সমর্থন করে না। এটি করার ফলে সম্মতিযুক্ত সমস্যাগুলির কারণ হয়, যার ফলে সমস্ত পছন্দগুলি হারিয়ে যায়। এছাড়াও, MODE_MULTI_PROCESS আর সমর্থিত নয়।
স্যাম

@ সাম এই উত্তরটি 3 বছরের পুরানো, দয়া করে এটিকে ডাউন-ভোট দিন না, যদি এটি অ্যান্ড্রয়েডের সর্বশেষ সংস্করণগুলিতে আপনার পক্ষে কাজ করে না। সময় উত্তর লিখিত ছিল এটি করার সর্বোত্তম পন্থা।
শ্রীদত্ত কোঠারি

1
না, আপনি যখন এই উত্তরটি লিখেছিলেন তখনও এই পন্থাটি মাল্টি প্রসেসটি কখনও নিরাপদ ছিল না।
স্যাম

@ স্যাম যেমন বলেছে, সঠিকভাবে, ভাগ করা প্রিফগুলি কখনও নিরাপদ প্রক্রিয়াজাত হয়নি। শ্রদ্ধত্ত কোঠারি - আপনি যদি না পছন্দ করেন তবে আপনার ভুল উত্তরগুলি সরান (এটি কোনওভাবেই ওপি-র প্রশ্নের উত্তর দেয় না)। তবে, আপনি যদি এখনও কোনও প্রক্রিয়া নিরাপদে উপায়ে ভাগ করা প্রেফগুলি ব্যবহার করতে চান তবে আপনাকে তার উপরে একটি প্রক্রিয়া নিরাপদ বিমূর্ততা তৈরি করতে হবে অর্থাৎ একটি বিষয়বস্তু সরবরাহকারী, যা প্রক্রিয়া নিরাপদ, এবং এখনও আপনাকে স্থায়ী স্টোরেজ প্রক্রিয়া হিসাবে ভাগ করা পছন্দগুলি ব্যবহার করতে দেয়। , আমি এটি আগে করেছি এবং ছোট ডেটাসেট / পছন্দগুলির জন্য ন্যায্য ব্যবধানে স্ক্লাইটটি সম্পাদন করি।
মার্ক কেইন

1
@ মার্ককইন, যাইহোক, আমি আসলে এর জন্য সামগ্রী সরবরাহকারীদের ব্যবহার করার চেষ্টা করেছি এবং সামগ্রী সরবরাহকারীরা অ্যান্ড্রয়েড বাগের কারণে উত্পাদনে এলোমেলোভাবে ব্যর্থ হওয়ার ঝোঁক রেখেছিল, তাই এই দিনগুলিতে আমি প্রয়োজন অনুসারে কনফিগারেশনটিকে মাধ্যমিক প্রক্রিয়াগুলিতে সিঙ্ক করতে কেবল সম্প্রচারগুলি ব্যবহার করি।
স্যাম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.