একটি নির্বাহী AsyncTask বাতিল করার আদর্শ উপায়


108

আমি একটি পটভূমি থ্রেড ব্যবহার করে দূরবর্তী অডিও-ফাইল-আনয়ন এবং অডিও ফাইল প্লেব্যাক অপারেশন চালাচ্ছি AsyncTaskCancellableআনার অপারেশন চলমান সময়ের জন্য একটি অগ্রগতি বার দেখানো হয়।

AsyncTaskযখন ব্যবহারকারী অপারেশন বাতিল করে (বিরুদ্ধে সিদ্ধান্ত নেন) আমি রানটিকে বাতিল / বাতিল করতে চাই । এই জাতীয় মামলা পরিচালনা করার আদর্শ উপায় কী?

উত্তর:


76

শুধু আবিষ্কার করেছি যে AlertDialogs's boolean cancel(...);আমি সর্বত্র আসলে ব্যবহার করছি কিছুই করে না। গ্রেট।
তাই ...

public class MyTask extends AsyncTask<Void, Void, Void> {

    private volatile boolean running = true;
    private final ProgressDialog progressDialog;

    public MyTask(Context ctx) {
        progressDialog = gimmeOne(ctx);

        progressDialog.setCancelable(true);
        progressDialog.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                // actually could set running = false; right here, but I'll
                // stick to contract.
                cancel(true);
            }
        });

    }

    @Override
    protected void onPreExecute() {
        progressDialog.show();
    }

    @Override
    protected void onCancelled() {
        running = false;
    }

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

        while (running) {
            // does the hard work
        }
        return null;
    }

    // ...

}

55
দৌড়ানোর জন্য বুলিয়ান পতাকা তৈরির পরিবর্তে, আপনি কি এটি সরিয়ে ফেলতে পারবেন না এবং এটি (! isCanceled ()) এর পরেও তৈরি করতে পারবেন ???
কনফুসিয়াস

36
অনক্যান্সেলড () সম্পর্কিত ডকস থেকে: " বাতিল হওয়ার পরে ইউআই থ্রেডে চালানো (বুলিয়ান) শুরু করা হয়েছে এবং doInBackground (অবজেক্ট []) শেষ হয়েছে" " এর 'পরে' এর অর্থ হ'ল অনকেনসেলডে একটি পতাকা সেট করা এবং ডইনব্যাকগ্রাউন্ডে চেক করা কোনও অর্থহীন নয়।
লোপেক

2
@ কনফুসিয়াস ঠিক আছে, তবে ব্যাকগ্রাউন্ড থ্রেডটি বাধাগ্রস্ত হয় না, ধরুন চিত্র আপলোড করার সময় কেস আপলোডিং প্রক্রিয়া ব্যাকগ্রাউন্ডে অব্যাহত থাকে এবং আমরা পোস্টপ্যাক্সেকুট কল পাইনি।
उमेश

1
@ ড্যানহুলমে আমি বিশ্বাস করি যে আমি উত্তরে প্রদত্ত কোড স্নিপেটকে উল্লেখ করেছি, কনফুসিয়াসের মন্তব্যে নয় (যা সঠিক)।
লোপেক

4
হ্যাঁ, এই উত্তরটি কার্যকর হয় না । ডোইনব্যাকগ্রাউন্ডে, অন্যরা এখানে যেমন মন্তব্য while(running)করেছেন while(!isCancelled())সেভাবে প্রতিস্থাপন করুন।
matt5784

76

আপনি যদি গণনা করছেন :

  • আপনাকে isCancelled()পর্যায়ক্রমে চেক করতে হবে ।

আপনি যদি এইচটিটিপি অনুরোধ করছেন :

  • আপনার HttpGetবা এর উদাহরণটি সংরক্ষণ করুনHttpPost অন্য কোথাও (যেমন একটি পাবলিক ফিল্ড)।
  • ফোন করার পরে ফোন cancelকরুন request.abort()। এটি IOExceptionআপনার ভিতরে ফেলে দেওয়া হবে doInBackground

আমার ক্ষেত্রে আমার একটি সংযোজক শ্রেণি ছিল যা আমি বিভিন্ন অ্যাসিঙ্কটাস্কগুলিতে ব্যবহার করি। এটিকে সহজ রাখতে, আমি abortAllRequestsসেই শ্রেণিতে একটি নতুন পদ্ধতি যুক্ত করেছি এবং কল করার পরে সরাসরি এই পদ্ধতিটি কল করি cancel


আপনাকে ধন্যবাদ, এটি কাজ করে, তবে এই ক্ষেত্রে কীভাবে ব্যতিক্রম এড়ানো যায়?
বেগিপাস

আপনাকে অবশ্যই HttpGet.abort()একটি পটভূমি থ্রেড থেকে কল করতে হবে বা আপনি একটি পাবেন android.os.NetworkOnMainThreadException
সীমানা

@ রাইগিয়েল আপনি যদি এইচটিটিপি অনুরোধ করছেন, cancel(true)তবে অনুরোধটি বাধাগ্রস্ত করা উচিত নয় ? ডকুমেন্টেশন থেকে:If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.
স্টোর

HttpURLConnection.disconnect();
ওডে ব্রেইনার

আপনার যদি অ্যাসিঙ্কটাস্কে সিপিইউ গ্রাহক অপারেশন হয়, তাই আপনাকে অবশ্যই কল করতে হবে cancel(true)। আমি এটি ব্যবহার করেছি এবং এটি কাজ করে।
এসএমমোসাভি

20

জিনিসটি হ'ল AsyncTask.cancel () কলটি কেবলমাত্র আপনার টাস্কে অনন্যাসেল ফাংশনকে কল করে। আপনি এখানেই অনুরোধটি হ্যান্ডেল করতে চান।

আপডেট পদ্ধতিটি ট্রিগার করতে আমি এখানে একটি ছোট কাজ ব্যবহার করি

private class UpdateTask extends AsyncTask<Void, Void, Void> {

        private boolean running = true;

        @Override
        protected void onCancelled() {
            running = false;
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
            onUpdate();
        }

        @Override
        protected Void doInBackground(Void... params) {
             while(running) {
                 publishProgress();
             }
             return null;
        }
     }

2
এটি কাজ করবে তবে যৌক্তিকভাবে যখন আপনি সার্ভারের প্রতিক্রিয়াটির জন্য অপেক্ষা করছেন এবং আপনি সবেমাত্র ডিবি অপারেশন করেছিলেন তখন আপনার ক্রিয়াকলাপে সঠিক পরিবর্তনগুলি প্রতিবিম্বিত হওয়া উচিত। আমি এটিতে একটি ব্লগ লিখেছি, আমার উত্তর দেখুন।
বিকাশ

4
গৃহীত উত্তরের মন্তব্যে যেমন উল্লেখ করা হয়েছে, নিজের runningপতাকা তৈরি করার দরকার নেই । অ্যাসিঙ্কটাস্কের একটি অভ্যন্তরীণ পতাকা রয়েছে যা কাজটি বাতিল হয়ে যাওয়ার পরে সেট করা হয়। while (running)সঙ্গে প্রতিস্থাপন while (!isCancelled())বিকাশকারী.অ্যান্ড্রয়েডonCancelled() .com/references/android/os/ … সুতরাং এই সাধারণ ক্ষেত্রে আপনার ওভাররাইডের দরকার নেই ।
টুলমেকারস্টেভ

11

সাধারণ: একটি ব্যবহার করবেন না AsyncTaskAsyncTaskসংক্ষিপ্ত ক্রিয়াকলাপগুলির জন্য তৈরি করা হয়েছে যা দ্রুত শেষ হয় (দশক সেকেন্ড) এবং সুতরাং এটি বাতিল করার দরকার নেই। "অডিও ফাইল প্লেব্যাক" যোগ্যতা অর্জন করে না। এমনকি সাধারণ অডিও ফাইল প্লেব্যাকের জন্য আপনার পটভূমি থ্রেডের দরকারও নেই।


আপনি কি পরামর্শ দিচ্ছেন যে আমরা নিয়মিত জাভা থ্রেডটি ব্যবহার করি এবং অস্থির বুলেয়ান ভেরিয়েবল - প্রচলিত জাভা উপায় ব্যবহার করে থ্রেড রান করি?
সামুহ

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

10
@ ক্লন্ডিকে: "মাইক" কে সে সম্পর্কে আমার কোনও ধারণা নেই। "তবে এটি একটি গ্রহণযোগ্য উত্তর নয়" - আপনি আপনার মতে আপনাকে স্বাগতম are "অ্যাসিঙ্কটাস্কের একটি বাতিল পদ্ধতি রয়েছে এবং এটি কাজ করা উচিত" " - জাভাতে থ্রেড বাতিল করা ~ 15 বছর ধরে সমস্যা been অ্যান্ড্রয়েডের সাথে এর খুব বেশি কিছু করার নেই। আপনার "ফোর্স ক্লোজ" দৃশ্যের সম্মানের সাথে, এটি বুলিয়ান ভেরিয়েবলের মাধ্যমে সমাধান করা যেতে পারে, যা আপনি onPostExecute()কাজটি নিয়ে এগিয়ে যাওয়া উচিত কিনা তা পরীক্ষা করে দেখার জন্য।
কমন্সওয়্যার

1
@ তেজস্বী ইয়ারুকালাপুদি: এটি আরও বেশি যে এটি স্বয়ংক্রিয়ভাবে কিছুই করবে না। এই প্রশ্নের গৃহীত উত্তর দেখুন।
কমন্সওয়্যার

10
আপনি AsyncTask এ আপনার doInBackগ্রাউন্ডে পর্যায়ক্রমে আইসনসেলড পদ্ধতিটি পরীক্ষা করার কথা। ডক্সে এটি ঠিক আছে: ডেভেলপার.অ্যান্ড্রয়েড.
ক্রিস্টোফার পেরি

4

এটি করার একমাত্র উপায় হ'ল ক্যানসেলড () পদ্ধতির মান পরীক্ষা করা এবং প্লেব্যাক বন্ধ হয়ে গেলে এটি সত্য হয়ে যায়।


4

এইভাবে আমি আমার অ্যাসিঙ্কটাস্ককে
মূল পয়েন্টটি লিখি থ্রেড.স্লিপ (1) যুক্ত করা;

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

        Log.d(TAG, PRE + "url:" + params[0]);
        Log.d(TAG, PRE + "file name:" + params[1]);
        downloadPath = params[1];

        int returnCode = SUCCESS;
        FileOutputStream fos = null;
        try {
            URL url = new URL(params[0]);
            File file = new File(params[1]);
            fos = new FileOutputStream(file);

            long startTime = System.currentTimeMillis();
            URLConnection ucon = url.openConnection();
            InputStream is = ucon.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(is);

            byte[] data = new byte[10240]; 
            int nFinishSize = 0;
            while( bis.read(data, 0, 10240) != -1){
                fos.write(data, 0, 10240);
                nFinishSize += 10240;
                **Thread.sleep( 1 ); // this make cancel method work**
                this.publishProgress(nFinishSize);
            }              
            data = null;    
            Log.d(TAG, "download ready in"
                  + ((System.currentTimeMillis() - startTime) / 1000)
                  + " sec");

        } catch (IOException e) {
                Log.d(TAG, PRE + "Error: " + e);
                returnCode = FAIL;
        } catch (Exception e){
                 e.printStackTrace();           
        } finally{
            try {
                if(fos != null)
                    fos.close();
            } catch (IOException e) {
                Log.d(TAG, PRE + "Error: " + e);
                e.printStackTrace();
            }
        }

        return returnCode;
    }

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

0

আমাদের গ্লোবাল AsyncTask বর্গ ভেরিয়েবল

LongOperation LongOperationOdeme = new LongOperation();

এবং KEYCODE_BACK ক্রিয়া যা AsyncTask বাধা দেয়

   @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            LongOperationOdeme.cancel(true);
        }
        return super.onKeyDown(keyCode, event);
    }

এটা আমার জন্য কাজ করে.


0

আমি cancel(true)অযৌক্তিকভাবে আমার অ্যাসিঙ্ক কার্যগুলিতে বাধা দেওয়া পছন্দ করি না কারণ তাদের মুক্ত হওয়ার সংস্থান থাকতে পারে, যেমন সকেট বা ফাইল স্ট্রিম বন্ধ করা, স্থানীয় ডাটাবেসে ডেটা লেখা ইত্যাদি the অন্যদিকে, আমি এমন পরিস্থিতিতে পড়েছি যার মধ্যে অ্যাসিঙ্ক টাস্ক নিজেকে সময়ের কিছুটা শেষ করতে অস্বীকার করে, উদাহরণস্বরূপ কখনও কখনও যখন মূল কার্যকলাপটি বন্ধ হয়ে যায় এবং আমি অ্যাসিঙ্ক টাস্কটিকে ক্রিয়াকলাপের onPause()পদ্ধতির ভিতরে থেকে শেষ করার অনুরোধ করি । সুতরাং এটি কেবল কল করার বিষয় নয় running = false। আমাকে একটি মিশ্র সমাধানের জন্য যেতে হবে: উভয় কল করুন running = false, তারপরে অ্যাসিঙ্ক টাস্কটি কয়েক মিলি সেকেন্ড শেষ করতে হবে, এবং তারপরে হয় কল করুন cancel(false)বা cancel(true)

if (backgroundTask != null) {
    backgroundTask.requestTermination();
    try {
        Thread.sleep((int)(0.5 * 1000));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    if (backgroundTask.getStatus() != AsyncTask.Status.FINISHED) {
        backgroundTask.cancel(false);
    }
    backgroundTask = null;
}

পার্শ্ব ফল হিসাবে, doInBackground()শেষ হওয়ার পরে , কখনও কখনও onCancelled()পদ্ধতিটি বলা হয়, এবং কখনও কখনও onPostExecute()। তবে কমপক্ষে অ্যাসিঙ্ক টাস্ক সমাপ্তির নিশ্চয়তা রয়েছে।


একটি দৌড় অবস্থা মত চেহারা।
মিসানজেল

0

29 ই এপ্রিল '10-এ ইয়ানচেঙ্কোর জবাবের প্রসঙ্গে: এসিএনটাস্কের প্রতিটি সম্পাদনের সময় যখন 'ডোইনব্যাকগ্রাউন্ড' এর অধীনে আপনার কোডটি একাধিকবার কার্যকর করতে হবে তখন 'সময় (চলমান)' পদ্ধতির ব্যবহারটি ঝরঝরে। যদি 'doInBackground' এর অধীনে আপনার কোডটি AsyncTask এর প্রয়োগের সময় কেবল একবার কার্যকর করতে হয়, আপনার সমস্ত কোডকে 'doInBackground' এর অধীনে একটি 'চলমান' চলাকালীন ফাঁকে ব্যাকগ্রাউন্ড কোড (পটভূমি থ্রেড) চলমান থেকে থামবে না যখন অ্যাসিঙ্কটাস্ক নিজেই বাতিল হয়ে গেছে, কারণ 'যখন (চলমান)' শর্তটি কেবলমাত্র একবারের মধ্যে থাকা সমস্ত কোডের একবার মূল্যায়ন করা হবে যখন লুপটি অন্তত একবার কার্যকর করা হয়েছিল। আপনাকে (ক।) 'ডোইনব্যাকগ্রাউন্ড' এর অধীনে আপনার কোডগুলি একাধিক 'চলমান' চলাকালীন 'ব্লক' বা 'বি।) অসংখ্য' isCancelled 'সম্পাদন করা উচিতhttps://developer.android.com/references/android/os/AsyncTask.html

বিকল্পের জন্য (ক।) এইভাবে ইয়ানচেঙ্কোর উত্তর নিম্নরূপে পরিবর্তন করতে পারে:

public class MyTask extends AsyncTask<Void, Void, Void> {

private volatile boolean running = true;

//...

@Override
protected void onCancelled() {
    running = false;
}

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

    // does the hard work

    while (running) {
        // part 1 of the hard work
    }

    while (running) {
        // part 2 of the hard work
    }

    // ...

    while (running) {
        // part x of the hard work
    }
    return null;
}

// ...

বিকল্পের জন্য (খ।) 'DoInBackground' তে আপনার কোডটি এর মতো দেখতে পাবেন:

public class MyTask extends AsyncTask<Void, Void, Void> {

//...

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

    // part 1 of the hard work
    // ...
    if (isCancelled()) {return null;}

    // part 2 of the hard work
    // ...
    if (isCancelled()) {return null;}

    // ...

    // part x of the hard work
    // ...
    if (isCancelled()) {return null;}
}

// ...
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.