পটভূমি টাস্ক, প্রগতি ডায়লগ, ওরিয়েন্টেশন পরিবর্তন - 100% কার্যনির্বাহী সমাধান আছে কি?


235

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

এই জাতীয় সমস্যা হ্যান্ডেল করার সর্বোত্তম উপায় কী (ব্যাকগ্রাউন্ড থ্রেড থেকে ইউআই আপডেট করা যা ব্যবহারকারীদের ওরিয়েন্টেশন পরিবর্তন করলেও কার্যকর হয়)? গুগল থেকে কেউ কি কিছু "অফিসিয়াল সলিউশন" সরবরাহ করেছেন?


4
এই বিষয়ে আমার ব্লগ পোস্ট সাহায্য করতে পারে। এটি কনফিগারেশন পরিবর্তনগুলি জুড়ে দীর্ঘমেয়াদী কাজগুলি বজায় রাখা সম্পর্কে।
অ্যালেক্স লকউড


কেবল এফটিআর এখানে একটি সম্পর্কিত রহস্য আছে .. stackoverflow.com/q/23742412/294884
ফ্যাটি

উত্তর:


336

ধাপ # 1: আপনার করুন AsyncTaskএকটি staticনেস্টেড বর্গ, অথবা একটি সম্পূর্ণ পৃথক বর্গ, শুধু একটি অভ্যন্তরীণ (অ-স্ট্যাটিক নেস্টেড) বর্গ।

ধাপ # 2: আছে AsyncTaskসম্মুখের হোল্ড Activityএকটি ডাটা সদস্য কন্সট্রাকটর এবং সেটার মাধ্যমে সেট মাধ্যমে।

পদক্ষেপ # 3: তৈরি করার সময় AsyncTask, Activityনির্মাণকারীর কাছে বর্তমান সরবরাহ করুন ।

পদক্ষেপ # 4: আসল, এখন-চলমান ক্রিয়াকলাপ থেকে এটি আলাদা করার পরে onRetainNonConfigurationInstance(), ফিরে AsyncTaskআসুন।

পদক্ষেপ # 5: onCreate()যদি getLastNonConfigurationInstance()তা না হয় তবে nullএটি আপনার AsyncTaskশ্রেণিতে ফেলে দিন এবং আপনার নতুন ক্রিয়াকলাপটিকে কার্যের সাথে যুক্ত করতে আপনার সেটারকে কল করুন।

পদক্ষেপ # 6: এর থেকে ক্রিয়াকলাপের ডেটা সদস্যকে উল্লেখ করবেন না doInBackground()

আপনি যদি উপরের রেসিপিটি অনুসরণ করেন তবে এটি কার্যকর হবে। onProgressUpdate()এবং পরবর্তী এবং এর শেষের onPostExecute()মধ্যে স্থগিত করা হয় ।onRetainNonConfigurationInstance()onCreate()

কৌশলটি প্রদর্শনের জন্য এখানে একটি নমুনা প্রকল্প রয়েছে

আর একটি পদ্ধতি হ'ল খনন করা AsyncTaskএবং আপনার কাজটিকে একটিতে স্থানান্তর করা IntentService। এটি বিশেষত কার্যকর যদি কাজটি করা কাজ দীর্ঘ হতে পারে এবং ব্যবহারকারীরা ক্রিয়াকলাপের ক্ষেত্রে কী করেন তা বিবেচনা না করে (যেমন, একটি বৃহত ফাইল ডাউনলোড করা)। আপনি Intentক্রিয়াকলাপটি করা কাজটির প্রতিক্রিয়া জানাতে একটি আদেশিত সম্প্রচার ব্যবহার করতে পারেন (এটি যদি এখনও অগ্রভাগে থাকে) বা Notificationকাজটি হয়েছে কিনা তা ব্যবহারকারীকে জানাতে একটি বাড়াতে পারেন। এই ধাঁচে আরও একটি ব্লগ পোস্ট এখানে।


8
এই সাধারণ সমস্যাটিতে আপনার দুর্দান্ত উত্তরের জন্য অনেক ধন্যবাদ! কেবল পুরোপুরিভাবে বলতে গেলে, আপনি অ্যাসিঙ্কটাস্কের ক্রিয়াকলাপটি বিচ্ছিন্ন করতে হবে (নালায় সেট করতে হবে) the ধাপে আপনি যুক্ত করতে পারেন। যদিও এটি নমুনা প্রকল্পে চিত্রিত হয়েছে।
কেভিন গাউডিন

3
তবে যদি আমার ক্রিয়াকলাপের সদস্যদের অ্যাক্সেস থাকা দরকার?
ইউজিন

3
@ অ্যান্ড্রু: একটি স্ট্যাটিক অভ্যন্তর শ্রেণি বা এমন কিছু তৈরি করুন যা বেশ কয়েকটি বস্তুকে ধারণ করে এবং এটি ফিরিয়ে দেয়।
কমন্সওয়েয়ার

11
onRetainNonConfigurationInstance()অবচয় করা হয় এবং প্রস্তাবিত বিকল্পটি ব্যবহার করা হয় setRetainInstance(), তবে এটি কোনও বস্তু ফেরায় না। এর asyncTaskসাথে কনফিগারেশন পরিবর্তনটি পরিচালনা করা কি সম্ভব setRetainInstance()?
ইন্দ্রেক কোয়ে

10
@ সাইলারআর: একেবারে। আছে Fragmentহোল্ড AsyncTask। আছে Fragmentকল setRetainInstance(true)নিজেই উপর। আছে AsyncTaskএকমাত্র আলাপ Fragment। এখন, একটি কনফিগারেশন পরিবর্তনে, এটি Fragmentধ্বংস এবং পুনরায় তৈরি করা হয়নি (তত্প্রিয়তা সত্ত্বেও), এবং তাই AsyncTaskএটি কনফিগারেশন পরিবর্তন জুড়ে ধরে রাখা হয়।
কমন্সওয়্যার

13

গৃহীত উত্তরটি খুব সহায়ক ছিল, তবে এর কোনও অগ্রগতি ডায়ালগ নেই।

ভাগ্যক্রমে আপনার জন্য, পাঠক, আমি একটি অ্যাসিঙ্কটাস্কের একটি প্রগতি ডায়ালগ সহ একটি অত্যন্ত বিস্তৃত এবং কার্যকারী উদাহরণ তৈরি করেছি !

  1. ঘূর্ণন কাজ করে এবং ডায়লগটি টিকে থাকে।
  2. পিছনের বোতামটি টিপে (আপনি যদি এই আচরণটি চান) তবে আপনি টাস্ক এবং ডায়লগ বাতিল করতে পারেন।
  3. এটি টুকরা ব্যবহার করে।
  4. ক্রিয়াকলাপের নীচে খণ্ডের বিন্যাসটি যখন ডিভাইসটি ঘোরানো হয় তখন সঠিকভাবে পরিবর্তিত হয়।

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

হ্যাঁ নিশ্চিত নই যে আমি স্থির সদস্যদের সম্পর্কে এটি কেন রেখেছি, যেহেতু আমি আসলে তাদের ব্যবহার করেছি ... অদ্ভুত। সম্পাদিত উত্তর।
টিম্ম্ম্ম

আপনি দয়া করে আপনার লিঙ্ক আপডেট করতে পারেন? আমার সত্যিই এটি দরকার
রোমেন পেলারিন

দুঃখিত, আমার ওয়েবসাইট পুনরুদ্ধার করতে পারেনি - আমি শীঘ্রই এটি করব! কিন্তু ইতোমধ্যে এটা মূলত এই উত্তরে কোড হিসাবে একই stackoverflow.com/questions/8417885/...
Timmmm

1
লিঙ্কটি বোগাস; কোডটি কোথায় রয়েছে তার কোনও ইঙ্গিত ছাড়াই কেবল অকেজো সূচকে নিয়ে যায়।
ফ্র্যাক্টালবোজ

9

আমি মেনিফেস্ট ফাইলটি সম্পাদনা না করে এই দ্বিধাটির সমাধান খুঁজতে এক সপ্তাহ চেষ্টা করেছি to এই সমাধানের জন্য অনুমানগুলি হ'ল:

  1. আপনার সর্বদা একটি অগ্রগতি ডায়ালগ ব্যবহার করা প্রয়োজন
  2. একটি সময়ে কেবল একটি কাজ সম্পাদন করা হয়
  3. ফোনটি যখন ঘোরানো হয় এবং অগ্রগতি ডায়ালগটি স্বয়ংক্রিয়ভাবে খারিজ হয়ে যায় তখন আপনার কাজটি চালিয়ে যাওয়া প্রয়োজন।

বাস্তবায়ন

আপনাকে এই পোস্টের নীচে পাওয়া দুটি ফাইল আপনার কর্মক্ষেত্রে অনুলিপি করতে হবে। কেবল তা নিশ্চিত করুন:

  1. আপনার সমস্ত Activityপ্রসারিত করা উচিতBaseActivity

  2. আপনি যে কোনও সদস্যকে আপনার অ্যাক্সেস করতে হবে তা শুরু করার পরে onCreate(), ইন কল করা super.onCreate()উচিত ASyncTask। এছাড়াও, getContentViewId()ফর্ম লেআউট আইডি সরবরাহ করতে ওভাররাইড করুন ।

  3. ক্রিয়াকলাপ দ্বারা পরিচালিত ডায়লগ তৈরি করতে onCreateDialog() স্বাভাবিকের মতো ওভাররাইড করুন ।

  4. আপনার অ্যাসিঙ্কটাস্কগুলি তৈরি করতে একটি নমুনা স্থির অভ্যন্তর শ্রেণীর জন্য নীচের কোডটি দেখুন। আপনার ফলাফলটি পরে অ্যাক্সেস করার জন্য mResult এ সঞ্চয় করতে পারেন।


final static class MyTask extends SuperAsyncTask<Void, Void, Void> {

    public OpenDatabaseTask(BaseActivity activity) {
        super(activity, MY_DIALOG_ID); // change your dialog ID here...
                                       // and your dialog will be managed automatically!
    }

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

        // your task code

        return null;
    }

    @Override
    public boolean onAfterExecute() {
        // your after execute code
    }
}

এবং অবশেষে, আপনার নতুন কাজটি চালু করতে:

mCurrentTask = new MyTask(this);
((MyTask) mCurrentTask).execute();

এটাই! আমি আশা করি এই শক্তিশালী সমাধানটি কাউকে সহায়তা করবে।

বেসঅ্যাক্টিভিটি.জভা (নিজেকে আমদানি করার ব্যবস্থা করুন)

protected abstract int getContentViewId();

public abstract class BaseActivity extends Activity {
    protected SuperAsyncTask<?, ?, ?> mCurrentTask;
    public HashMap<Integer, Boolean> mDialogMap = new HashMap<Integer, Boolean>();

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

        setContentView(getContentViewId());

        mCurrentTask = (SuperAsyncTask<?, ?, ?>) getLastNonConfigurationInstance();
        if (mCurrentTask != null) {
            mCurrentTask.attach(this);
            if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
                && mDialogMap.get((Integer) mCurrentTask.dialogId)) {
        mCurrentTask.postExecution();
            }
        }
    }

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
    super.onPrepareDialog(id, dialog);

        mDialogMap.put(id, true);
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        if (mCurrentTask != null) {
            mCurrentTask.detach();

            if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
                && mDialogMap.get((Integer) mCurrentTask.dialogId)) {
                return mCurrentTask;
            }
        }

        return super.onRetainNonConfigurationInstance();
    }

    public void cleanupTask() {
        if (mCurrentTask != null) {
            mCurrentTask = null;
            System.gc();
        }
    }
}

SuperAsyncTask.java

public abstract class SuperAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
    protected BaseActivity mActivity = null;
    protected Result mResult;
    public int dialogId = -1;

    protected abstract void onAfterExecute();

    public SuperAsyncTask(BaseActivity activity, int dialogId) {
        super();
        this.dialogId = dialogId;
        attach(activity);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mActivity.showDialog(dialogId); // go polymorphism!
    }    

    protected void onPostExecute(Result result) {
        super.onPostExecute(result);
        mResult = result;

        if (mActivity != null &&
                mActivity.mDialogMap.get((Integer) dialogId) != null
                && mActivity.mDialogMap.get((Integer) dialogId)) {
            postExecution();
        }
    };

    public void attach(BaseActivity activity) {
        this.mActivity = activity;
    }

    public void detach() {
        this.mActivity = null;
    }

    public synchronized boolean postExecution() {
        Boolean dialogExists = mActivity.mDialogMap.get((Integer) dialogId);
        if (dialogExists != null || dialogExists) {
            onAfterExecute();
            cleanUp();
    }

    public boolean cleanUp() {
        mActivity.removeDialog(dialogId);
        mActivity.mDialogMap.remove((Integer) dialogId);
        mActivity.cleanupTask();
        detach();
        return true;
    }
}

4

গুগল থেকে কেউ কি কিছু "অফিসিয়াল সলিউশন" সরবরাহ করেছেন?

হ্যাঁ.

সমাধানটি হ'ল কিছু অ্যাপ্লিকেশন আর্কিটেকচার প্রস্তাবের চেয়ে বরং কিছু কোড

তারা প্রস্তাবিত 3 ডিজাইনের ধরণ যা কোনও অ্যাপ্লিকেশন রাষ্ট্র নির্বিশেষে কোনও অ্যাপ্লিকেশনটিকে একটি সার্ভারের সাথে সিঙ্কে কাজ করার অনুমতি দেয় (এটি ব্যবহার করবে অ্যাপ্লিকেশনটি শেষ করেও, ব্যবহারকারী স্ক্রিন পরিবর্তন করে, অ্যাপটি সমাপ্ত হয়, প্রতিটি সম্ভাব্য রাজ্যে যেখানে একটি পটভূমি ডেটা অপারেশন বাধা দেওয়া যেতে পারে, এটি এটি কভার করে)

ভার্জিল ডবজানসি গুগল আই / ও ২০১০ চলাকালীন অ্যান্ড্রয়েড আরএসটি ক্লায়েন্ট অ্যাপ্লিকেশন ভাষণে এই প্রস্তাবটি ব্যাখ্যা করা হয়েছে । এটি 1 ঘন্টা দীর্ঘ, তবে এটি দেখার পক্ষে অত্যন্ত মূল্যবান।

এর ভিত্তিটি এমন একটিতে নেটওয়ার্ক ক্রিয়াকলাপকে বিমূর্ত করা যা অ্যাপ্লিকেশনটিতে Serviceযে কোনওটির কাছে স্বতন্ত্রভাবে কাজ করে Activity। আপনি ডাটাবেস সাথে কাজ করেন, তাহলে ব্যবহার ContentResolverএবং Cursorআপনি একটি আউট-অফ-বক্স দিতে হবে অবজারভার প্যাটার্ন যে কোনো অতিরিক্ত যুক্তিবিজ্ঞান ছাড়া UI 'তে আপডেট করতে, একবার আপনি সংগৃহীত দূরবর্তী তথ্য দিয়ে আপনার স্থানীয় ডাটাবেসের আপডেট সুবিধাজনক। অপারেশন পরবর্তী কোনও কোড কোডব্যাকের মাধ্যমে চলে যাবে Service(আমি এর জন্য একটি ResultReceiverসাবক্লাস ব্যবহার করি )।

যাইহোক, আমার ব্যাখ্যাটি আসলে বেশ অস্পষ্ট, আপনার স্পষ্টভাবে বক্তব্যটি দেখা উচিত।


2

যদিও মার্কের (কমন্সওয়্যার) উত্তর প্রকৃতপক্ষে ওরিয়েন্টেশন পরিবর্তনের জন্য কাজ করে, ক্রিয়াকলাপটি সরাসরি ধ্বংস হয়ে গেলে (যেমন কোনও ফোন কল করার ক্ষেত্রে) এটি ব্যর্থ হয়।

আপনার ASyncTask কে রেফারেন্স করার জন্য অ্যাপ্লিকেশন অবজেক্টটি ব্যবহার করে আপনি ওরিয়েন্টেশন পরিবর্তনগুলি এবং বিরল ধ্বংস হওয়া ক্রিয়াকলাপ ইভেন্টগুলি পরিচালনা করতে পারেন।

সমস্যা এবং সমাধানের একটি দুর্দান্ত ব্যাখ্যা এখানে রয়েছে :

এটি বের করার জন্য ক্রেডিট পুরোপুরি রায়ানকে যায়।


1

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


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

ধন্যবাদ, আমি পরিস্থিতি সম্পর্কে জানতাম তবে সেটরেটাইন ইনস্ট্যান্স () সম্পর্কে নয়। আমি যা বুঝতে পারি না তা হ'ল আপনার দাবী যে গুগল এই প্রশ্নটিতে জিজ্ঞাসিত সমস্যাগুলি সমাধান করতে ব্যবহার করেছে। আপনি কি তথ্যের উত্স লিঙ্ক করতে পারেন? ধন্যবাদ।
জেজে_


#RetainNonCfigrationInstance () এই ফাংশনটিকে নিখুঁতভাবে একটি অপ্টিমাইজেশন হিসাবে ডাকা হয়, এবং আপনাকে অবশ্যই এটি আহ্বানের উপর নির্ভর করা উচিত নয়। <একই উত্স থেকে: developer.android.com/references/android/app/…
ধনঞ্জয় এম

0

আপনার ক্রিয়াকলাপ হ্যান্ডলার ব্যবহার করে সমস্ত ক্রিয়াকলাপ ক্রিয়াকলাপ করা উচিত। সুতরাং আপনি যদি কিছু থ্রেডে থাকেন তবে আপনার চালনার যোগ্য তৈরি করা উচিত এবং অ্যাক্টিভিটির হ্যান্ডলার ব্যবহার করে পোস্ট করা উচিত। অন্যথায় আপনার অ্যাপ কখনও কখনও মারাত্মক ব্যতিক্রম সহ ক্রাশ হবে।


0

এটি আমার সমাধান: https://github.com/Gotchamoh/Android-AncncTask- প্রোগ্রেসডায়ালগ

মূলত পদক্ষেপগুলি হ'ল:

  1. আমি onSaveInstanceStateযদি কাজটি এখনও প্রক্রিয়াজাত হয় তবে সংরক্ষণ করতে ব্যবহার করি ।
  2. ইন onCreateযদি এটা সংরক্ষিত ছিল আমি কাজের পেতে।
  3. ইন onPauseআমি পরিত্যাগ ProgressDialogযদি এটা দেখানো হয়।
  4. ইন onResumeআমি দেখাতে ProgressDialogযদি টাস্ক এখনও প্রক্রিয়া হচ্ছে।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.