সতর্কতা: এই অ্যাসিঙ্কটাস্ক ক্লাসটি স্থির হওয়া উচিত বা ফাঁস হতে পারে


270

আমি আমার কোডে একটি সতর্কতা পাচ্ছি যা এতে বলেছে:

এই অ্যাসিঙ্কটাস্ক ক্লাসটি স্থির হওয়া উচিত বা ফাঁস হতে পারে (বেনামে android.os.AsyncTask)

সম্পূর্ণ সতর্কতা হ'ল:

এই অ্যাসিঙ্কটাস্ক ক্লাসটি স্ট্যাটিক হওয়া উচিত বা ফাঁস হতে পারে (বেনামে android.os.AsyncTask) একটি স্ট্যাটিক ফিল্ড প্রাসঙ্গিকগুলি ফাঁস করবে। অ স্থিতিশীল অভ্যন্তর শ্রেণীর বাইরের শ্রেণিতে একটি অন্তর্নিহিত উল্লেখ রয়েছে reference যদি বাহ্যিক শ্রেণীর উদাহরণস্বরূপ কোনও খণ্ড বা ক্রিয়াকলাপ হয়, তবে এই রেফারেন্সটির অর্থ দীর্ঘকাল ধরে চলমান হ্যান্ডলার / লোডার / কার্যটি ক্রিয়াকলাপের জন্য একটি রেফারেন্স রাখবে যা এটিকে আবর্জনা সংগ্রহ হতে বাধা দেয়। একইভাবে, ক্রিয়াকলাপগুলির সরাসরি ক্ষেত্রের উল্লেখ এবং এই দীর্ঘকালীন দৃষ্টান্তগুলি থেকে খণ্ডগুলি ফাঁস হওয়ার কারণ হতে পারে। ভিউমোডেল ক্লাসগুলি ভিউ বা অ্যাপ্লিকেশনবিহীন প্রসঙ্গগুলিকে কখনই নির্দেশ করবে না।

এটি আমার কোড:

 new AsyncTask<Void,Void,Void>(){

        @Override
        protected Void doInBackground(Void... params) {
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    mAdapter.notifyDataSetChanged();
                }
            });

            return null;
        }
    }.execute();

আমি কীভাবে এটি সংশোধন করব?


2
এই androiddesignpatterns.com/2013/01/… পড়ার কারণে কেন এটি স্থির হওয়া উচিত তার একটি ইঙ্গিত দেওয়া উচিত
রঘুনন্দন

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

1
কোটলিনে এই সমস্যার সমাধান কী?
তপন এইচপি

কোন উত্তরটি গ্রহণযোগ্য উত্তর হওয়া উচিত দয়া করে তা পুনর্বিবেচনা করুন। নীচে উত্তর দেখুন।
gaমেগা

আমার ক্ষেত্রে, আমি এই সতর্কতাটি একটি একক সিলেটের কাছ থেকে পেয়েছি যার ক্রিয়াকলাপের কোনও সরাসরি উল্লেখ নেই (এটি myActivity.getApplication()রুমেলবি ক্লাস এবং অন্যান্য ক্লাস আরম্ভ করার জন্য সিঙ্গেলনের বেসরকারী নির্মাণকারীকে আউটপুট প্রাপ্ত করে )। আমার ভিউমোডেলস ডিবিতে কিছু ক্রিয়াকলাপ চালানোর জন্য একক রেফারেন্স হিসাবে সিঙ্গেলটন উদাহরণ পান। সুতরাং, ভিউমোডেলগুলি সিঙ্গলটন প্যাকেজটি আমদানি করে android.app.Application, এর মধ্যে একটি করেও android.app.Activity। যেহেতু "সিঙ্গেলটন" এর কাজ করতে সেই ভিউমোডেলগুলি আমদানি করার দরকার নেই, তবুও, মেমরি ফাঁস হতে পারে?
SebasSBM

উত্তর:


64

অ স্থিতিশীল অভ্যন্তর শ্রেণিগুলি সমন্বিত শ্রেণীর একটি রেফারেন্স ধারণ করে। আপনি যখন AsyncTaskঅভ্যন্তরীণ শ্রেণি হিসাবে ঘোষণা করেন, এটি ধারণক্ষম শ্রেণীর চেয়ে দীর্ঘতর থাকতে পারে Activity। এটি ধারণক্ষম শ্রেণীর অন্তর্নিহিত রেফারেন্সের কারণে এটি। এটি ক্রিয়াকলাপটি আবর্জনা সংগ্রহ করা থেকে আটকাবে, সুতরাং মেমরি ফাঁস হবে।

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


1
সমাধান নিজেই সতর্কতার মধ্যে রয়েছে। হয় স্ট্যাটিক নেস্টেড ক্লাস বা একটি শীর্ষ স্তরের শ্রেণি ব্যবহার করুন।
আনন্দ

3
@ কেয়ারনিমাওয়াত আমার ধারণা আপনি আপনার ক্রিয়াকলাপের জন্য দুর্বল রেফারেন্সটি দিতে পারেন
পিটারচাউলা

42
সুতরাং AsyncTask ব্যবহার করার কী লাভ? যদি থ্রেডের রান পদ্ধতিতে নতুন থ্রেড এবং হ্যান্ডেলআর পোস্ট বা ভিউ.পস্ট (ইউআই আপডেট করতে) চালানো সহজ হয়। যদি অ্যাসিঙ্কটাস্ক স্থির বা শীর্ষ স্তরের শ্রেণি হয় তবে এর থেকে প্রয়োজনীয় ভেরিয়েবলগুলি / পদ্ধতিগুলি অ্যাক্সেস করা কঠিন
ব্যবহারকারী 924

8
এটি ব্যবহারের সঠিক উপায় কীভাবে কোনও কোড সরবরাহ করা হয়নি। আমি সেখানে কখনও স্থির রাখার চেষ্টা করেছি, তবে আরও সতর্কতা এবং ত্রুটি দেখাবে
কাসনাডি

19
তাই এ আরো দরকারী উত্তর @Anand দয়া করে এই উত্তর মুছতে stackoverflow.com/a/46166223/145119 উপরের হতে পারে।
মিঠাল্দু

555

স্থিতিশীল অভ্যন্তর AsyncTask বর্গ কীভাবে ব্যবহার করবেন

ফাঁস রোধ করতে, আপনি অভ্যন্তর শ্রেণীর স্থির করতে পারেন। যদিও এর সাথে সমস্যাটি হ'ল কার্যকলাপের ইউআই ভিউ বা সদস্য ভেরিয়েবলগুলিতে আপনার আর অ্যাক্সেস নেই। আপনি একটি রেফারেন্সে পাস করতে পারেন Contextতবে তারপরে আপনি মেমরি ফাঁস হওয়ার একই ঝুঁকিটি চালান। (অ্যাসিঙ্কটাস্ক ক্লাসটির কাছে দৃ strong় উল্লেখ থাকলে অ্যান্ড্রয়েড ক্রিয়াকলাপ বন্ধ হয়ে যাওয়ার পরে তা সংগ্রহ করতে পারে না)) সমাধানটির ক্রিয়াকলাপে (বা আপনার যা Contextপ্রয়োজন) দুর্বল উল্লেখ করা ।

public class MyActivity extends AppCompatActivity {

    int mSomeMemberVariable = 123;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // start the AsyncTask, passing the Activity context
        // in to a custom constructor 
        new MyTask(this).execute();
    }

    private static class MyTask extends AsyncTask<Void, Void, String> {

        private WeakReference<MyActivity> activityReference;

        // only retain a weak reference to the activity 
        MyTask(MyActivity context) {
            activityReference = new WeakReference<>(context);
        }

        @Override
        protected String doInBackground(Void... params) {

            // do some long running task...

            return "task finished";
        }

        @Override
        protected void onPostExecute(String result) {

            // get a reference to the activity if it is still there
            MyActivity activity = activityReference.get();
            if (activity == null || activity.isFinishing()) return;

            // modify the activity's UI
            TextView textView = activity.findViewById(R.id.textview);
            textView.setText(result);

            // access Activity member variables
            activity.mSomeMemberVariable = 321;
        }
    }
}

মন্তব্য

  • যতদূর আমি জানি, এই ধরণের মেমরি ফুটো বিপদটি সর্বদা সত্য, তবে আমি কেবল অ্যান্ড্রয়েড স্টুডিও 3.0 এ সতর্কতাটি দেখতে শুরু করেছি started অনেকগুলি মূল AsyncTaskটিউটোরিয়াল এখনও এটির সাথে ডিল করে না (দেখুন এখানে , এখানে , এখানে এবং এখানে )।
  • আপনি যদি AsyncTaskশীর্ষ স্তরের শ্রেণি হন তবে আপনিও অনুরূপ পদ্ধতি অনুসরণ করবেন । একটি স্থিতিশীল অভ্যন্তর শ্রেণিটি মূলত জাভার শীর্ষ স্তরের শ্রেণির মতো।
  • আপনার যদি ক্রিয়াকলাপটি নিজেই প্রয়োজন না হয় তবে এখনও প্রসঙ্গে চান (উদাহরণস্বরূপ, একটি প্রদর্শন Toastকরতে), আপনি অ্যাপ্লিকেশন প্রসঙ্গে একটি রেফারেন্সে পাস করতে পারেন। এক্ষেত্রে AsyncTaskকনস্ট্রাক্টর এর মতো দেখতে পাবেন:

    private WeakReference<Application> appReference;
    
    MyTask(Application context) {
        appReference = new WeakReference<>(context);
    }
  • এই সতর্কতাটিকে উপেক্ষা করার জন্য এবং কেবল অ-স্থিত শ্রেণীর ব্যবহারের জন্য কিছু যুক্তি রয়েছে। সর্বোপরি, অ্যাসিঙ্কটাস্কটি খুব স্বল্প সময়ের জন্য (দীর্ঘতম কয়েক সেকেন্ড) থাকার জন্য পরিকল্পনা করা হয়েছে এবং এটি যেভাবেই শেষ হবে না কেন এটি ক্রিয়াকলাপের সাথে তার রেফারেন্স প্রকাশ করবে। দেখুন এই এবং এই
  • দুর্দান্ত নিবন্ধ: কীভাবে প্রসঙ্গে ফাঁস করবেন: হ্যান্ডলার এবং ইনার ক্লাসগুলি

Kotlin

কোটলিনে কেবল অভ্যন্তর শ্রেণীর কীওয়ার্ডটি অন্তর্ভুক্ত করবেন নাinner । এটি এটি ডিফল্টরূপে স্থির করে তোলে।

class MyActivity : AppCompatActivity() {

    internal var mSomeMemberVariable = 123

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // start the AsyncTask, passing the Activity context
        // in to a custom constructor
        MyTask(this).execute()
    }

    private class MyTask
    internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {

        private val activityReference: WeakReference<MyActivity> = WeakReference(context)

        override fun doInBackground(vararg params: Void): String {

            // do some long running task...

            return "task finished"
        }

        override fun onPostExecute(result: String) {

            // get a reference to the activity if it is still there
            val activity = activityReference.get()
            if (activity == null || activity.isFinishing) return

            // modify the activity's UI
            val textView = activity.findViewById(R.id.textview)
            textView.setText(result)

            // access Activity member variables
            activity.mSomeMemberVariable = 321
        }
    }
}

1
@ মনোজফ্রেকজ, না, আসলে আপনি যে ক্রিয়াকলাপটি উত্তীর্ণ হয়েছিল তার দুর্বল উল্লেখটি ব্যবহার করে ইউআই আপডেট করতে পারবেনonPostExecute । উপরের কোডে আমার পদ্ধতিটি আবার পরীক্ষা করে দেখুন । আপনি দেখতে পাচ্ছেন যে আমি TextViewসেখানে ইউআই আপডেট করেছি । activity.findViewByIdআপনার ইউআই উপাদান যা আপডেট করতে হবে তা কেবলমাত্র একটি রেফারেন্স পেতে ব্যবহার করুন ।
সুরগাচ

7
+1 টি। এটি আমি দেখেছি সবচেয়ে ভাল এবং পরিষ্কার সমাধান! কেবলমাত্র, আপনি পোস্টপ্যাক্সেকিউট পদ্ধতিতে ইউআই সংশোধন করতে চাইলে ক্রিয়াকলাপটি ধ্বংস হচ্ছে কিনা তাও আপনার পরীক্ষা করা উচিত: কার্যকলাপ.আইসফিনিশিং ()
জাপোটেক

1
বিঃদ্রঃ! এই উত্তরটি ব্যবহার করার সময়, আমি নল পয়েন্টার ব্যতিক্রমগুলিতে চালিয়ে যেতে থাকি কারণ ডইনব্যাকগ্রাউন্ড অপারেশনটি স্মৃতিশক্তি ছিল, আবর্জনা সংগ্রহকে ট্রিগার করেছিল, দুর্বল রেফারেন্স সংগ্রহ করেছিল এবং অ্যাসিনটাস্ককে হত্যা করেছিল। আপনি যদি জানেন যে আপনার ব্যাকগ্রাউন্ড অপারেশনগুলি আরও মেমরি নিবিড় হয় তবে আপনি দুর্বলগুলির পরিবর্তে একটি সফটফারেন্স ব্যবহার করতে চাইতে পারেন।
PGMacDesign

2
@ সানি, ক্রিয়াকলাপের পরিবর্তে টুকরো টুকরো টুকরো রেফারেন্সে পাস করুন। আপনি activity.isFinishing()চেকটি নেবেন এবং সম্ভবত এটি একটি fragment.isRemoving()চেকের সাথে প্রতিস্থাপন করবেন । যদিও আমি সম্প্রতি টুকরো টুকরো করে খুব বেশি কাজ করিনি।
সুরগাচ

1
@ বাশান, (1) যদি বাইরের শ্রেণিটি কোনও ক্রিয়াকলাপ না হয় তবে আপনার নির্মাত্রে AsyncTaskআপনি আপনার বহিরাগত শ্রেণির রেফারেন্সে পাস করেন। এবং এর সাথে doInBackground()আপনি বাইরের শ্রেণীর সাথে একটি রেফারেন্স পেতে পারেন MyOuterClass ref = classReference.get()। জন্য পরীক্ষা করুন null। (২) onPostExecute()আপনি পটভূমি টাস্কের ফলাফলগুলি সহ কেবলমাত্র ইউআই আপডেট করছেন। এটি আপনি যে কোনও সময় যেমন ইউআই আপডেট করেন ঠিক তেমন। তদন্তটি activity.isFinishing()কেবলমাত্র কার্যকলাপের ইতিমধ্যে শেষ করা শুরু হয়নি তা নিশ্চিত করার জন্য, এই ক্ষেত্রে ইউআই আপডেট করা অর্থহীন।
সুরগাচ

23

এই AsyncTaskশ্রেণিটি স্থির হওয়া উচিত বা ফাঁস হতে পারে কারণ

  • Activityধ্বংস হয়ে গেলে , AsyncTask(উভয় staticবা non-static) এখনও চলছে
  • অভ্যন্তর শ্রেণিটি যদি non-static( AsyncTask) শ্রেণি হয় তবে এর বহিরাগত শ্রেণি ( Activity) এর উল্লেখ থাকবে ।
  • যদি কোনও অবজেক্টের কোনও রেফারেন্স পয়েন্ট না থাকে তবে এটি Garbage Collectedছেড়ে দেবে। যদি কোনও বস্তু অব্যবহৃত থাকে এবং এটি প্রকাশ Garbage Collected করতে না পারে => মেমরি ফাঁস

=> যদি AsyncTaskহয় non-static, Activityঘটনা প্রকাশ করবে না এটা ধ্বংস করা হয় => লিক

অ্যাসিঙ্কটাস্ককে ফাঁস ছাড়াই স্থির শ্রেণি হিসাবে তৈরি করার পরে আপডেট ইউআইয়ের সমাধান

1) WeakReference@ সুরগাচের উত্তরের মতো ব্যবহার করুন
2) Activity(থেকে) এর রেফারেন্স প্রেরণ করুন এবং সরানAsyncTask

public class NoLeakAsyncTaskActivity extends AppCompatActivity {
    private ExampleAsyncTask asyncTask;

    @Override 
    protected void onCreate(Bundle savedInstanceState) {
        ...

        // START AsyncTask
        asyncTask = new ExampleAsyncTask();
        asyncTask.setListener(new ExampleAsyncTask.ExampleAsyncTaskListener() {
            @Override
            public void onExampleAsyncTaskFinished(Integer value) {
                // update UI in Activity here
            }
        });
        asyncTask.execute();
    }

    @Override
    protected void onDestroy() {
        asyncTask.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
        super.onDestroy();
    }

    static class ExampleAsyncTask extends AsyncTask<Void, Void, Integer> {
        private ExampleAsyncTaskListener listener;

        @Override
        protected Integer doInBackground(Void... voids) {
            ...
            return null;
        }

        @Override
        protected void onPostExecute(Integer value) {
            super.onPostExecute(value);
            if (listener != null) {
                listener.onExampleAsyncTaskFinished(value);
            }
        }

        public void setListener(ExampleAsyncTaskListener listener) {
            this.listener = listener;
        }

        public interface ExampleAsyncTaskListener {
            void onExampleAsyncTaskFinished(Integer value);
        }
    }
}


5
@ সুরগ্যাচ আপনার লিঙ্কটিতে বলা হয়েছে যে, অনড্রেস্ট্রয় বলা হওয়ার গ্যারান্টি নেই তবে সিস্টেমটি প্রক্রিয়াটি মেরে ফেললে একমাত্র পরিস্থিতি তখনই হয় না, তাই সমস্ত সংস্থান যেভাবেই মুক্ত হয়। সুতরাং, এখানে সংরক্ষণ করবেন না, তবে আপনি এখানে একটি উত্স রিলিজ করতে পারেন।
অ্যাঞ্জেলো ফুকস

2
অ-স্থির অ্যাসিঙ্কটাস্ক ব্যবহারের ক্ষেত্রে, কেন আমরা ঠিক এখনই এসিঙ্কটাস্ক ইনস্ট্যান্স ভেরিয়েবলটিকে NULL তে সেট করতে পারি না। এটি কী GC কে অ্যাক্টিভিটি মুক্ত করতে বলবে যদিও AsyncTask চলছে?
হানিফ

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