отмена AsyncTask, которая использует ProgressDialog - PullRequest
2 голосов
/ 10 мая 2011

У меня есть AsyncTask, который запускает класс DatabaseHelper из DoinBackground, который копирует базу данных SQLite из каталога / assets в каталог приложения (/ database).

В preExecute () я запускаю progressDialog.Когда части вспомогательного класса DB завершены, процесс DoinBackground обновляет progressDialog.

Когда устройство поворачивается, насколько я понимаю, мне нужно закрыть диалоговое окно, отменить AsyncTask, а затем снова запустить обав onResume () после завершения поворота.

Первая проблема - когда я вызываю AsyncTask.cancel (), происходит событие onCancel (), но AsyncTask продолжает работать.Я знаю, потому что LogCat показывает вывод из моего помощника БД задолго после окончания вращения.Пользовательский интерфейс можно использовать после ротации, потому что progressDialog ушел, но БД все еще кажется, что копирование копирует, поэтому это бесполезно.я просто позволю этой вещи работать в фоновом режиме, чтобы не беспокоиться об этом?Есть ли способ снова подключить (все еще выполняющийся) процесс DoinBackground к progressDialog?

Спасибо

    package com.test.helloasync;

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;

    import android.app.Activity;
    import android.app.ProgressDialog;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.os.SystemClock;
    import android.util.Log;

    public class HelloAsync extends Activity
    {
        myVars v;
        protected fileCopyTask fct;
        private final String TAG = "** HelloAsync **";
        private final String DBNAME = "foo.png";  // need png extension: Data exceeds UNCOMPRESS_DATA_MAX (5242880 vs 1048576)


        @Override
        public void onCreate (Bundle savedInstanceState)
        {
            super.onCreate (savedInstanceState);
            setContentView (R.layout.main); 
            restoreFromObject ();
        }

        /* (non-Javadoc)
         * @see android.app.Activity#onResume()
         */
        @Override
        protected void onResume ()
        {
           // TODO Auto-generated method stub
            Log.d (TAG, "onResume()");

            // only start NEW task if not cancelled and file has not been copied yet
            if ((v.taskCancelled == false) && (v.fileCopied == false))
            {
                fct = new fileCopyTask ();
                fct.execute ();
            }

            // show progressdialog if we were cancelled becuase asynctask will continue by itself
            if ((v.taskCancelled == true) && (v.fileCopied == false))
            {
                Log.d (TAG, "onAttachedToWindow(): launching fct");
                v.pd.show ();

                // may need to check status here to make sure it was cancelled and not something else...
                Log.d (TAG, "fct cancel status is " + fct.isCancelled ());
            }

           super.onResume ();
        }

        /**
         * saves myVars class during rotation
         */
        @Override
        public Object onRetainNonConfigurationInstance ()
        {
            Log.d (TAG, "onRetainNonConfigurationInstance(): saving  myVars objects");

            // close db transfer dialogs if showing so we don't cause a UI error
            if (v.pd != null)
                if (v.pd.isShowing ())
                {
                    v.taskCancelled = true;
                    v.pd.cancel ();
                }

            // save task to myVars so we can use it onRestoreInstanceState
            v.fct = fct;

            return (v);
        }


        /*
         * restores myVars class after rotation
         */
        private void restoreFromObject ()
        {
            Log.d (TAG, "restoreFromObject(): retrieving myVars object");
            v = (myVars) getLastNonConfigurationInstance ();

            // initialize myVars object (v) first time program starts
            if (v == null)
                v = new myVars ();
            else
            {
                Log.d (TAG, "myVars already initialized");
                fct = (fileCopyTask) v.fct;
            }
        }


        /**
         * 
         * copy a file from /assets to /data/data/com.blah.blah/databases
         *
         */
        private class fileCopyTask extends AsyncTask<Integer, Void, Void>
        {
            // on UI thread here
            protected void onPreExecute ()
            {
                Log.d (TAG, "onPreExecute()" );

                // only show this when db has not been copied
                // set initDbDone to false prir to call if downloading a new DB
                v.pd = new ProgressDialog (HelloAsync.this);
                v.pd.setProgressStyle (ProgressDialog.STYLE_HORIZONTAL);
                v.pd.setMessage ("Initializing Database");
                v.pd.show ();
            }

            /**
             * opens file in assets/ directory and counts the bytes in it so we can have an actual progress bar
             * 
             * @return size
             */
            private int getAssetSize ()
            {
                int size = 0;

                try
                {
                    InputStream fin = getBaseContext ().getAssets ().open (DBNAME);
                    byte [] buffer = new byte [1024];
                    int length = 0;
                    while ((length = fin.read (buffer)) > 0)
                        size += length;

                    fin.close ();
                }
                catch (IOException ioe)
                {
                    Log.d (TAG, "fileCopyTask(): asset size failed: ioex :" + ioe);
                    size = 0;
                }

                Log.d (TAG, "   fileCopyTask(): asset size is " + size);
                return (size);
            }

            @Override
            protected Void doInBackground (Integer... params)
            {
                Log.d (TAG, "doInBackground: +++++++++++++++++++++++++++++++++");

                try
                {
                    int inputsize = getAssetSize ();

                    // this is the input file in the assets directory. We have no idea how big it is.
                    InputStream fin = getBaseContext ().getAssets ().open (DBNAME);

                    // this is the destination database file on the android device
                    File dbFile = getBaseContext ().getDatabasePath (DBNAME);

                    // check if destination directory exists 
                    String parent = dbFile.getParent ();

                    // create the desitination directory if it does not exist in /data/data/blah.. (on device)
                    if (dbFile.exists () == false)
                    {
                        boolean result = new File (parent).mkdir ();
                        Log.d (TAG, "   fileCopyTask(): mkdir() result is " + result);
                    }

                    // this is the output file in the databases/ subdirectory of the app directory (on device)
                    OutputStream fout = new FileOutputStream (dbFile);

                    // transfer bytes from the inputfile to the outputfile
                    byte [] buffer = new byte [4096];
                    int length;
                    int bytesCopied = 0;
                    while ((length = fin.read (buffer)) > 0)
                    {
                        fout.write (buffer, 0, length);
                        bytesCopied += length;
                        float b = (float) (bytesCopied * 1.0);
                        float i = (float) (inputsize * 1.0);
                        float pctdone = (float) ((b / i) * 100.0);
                        int pct = (int) (pctdone);

                        // updating every 4k seems to really slow things down so do it every 5 chunks
                        if ((pct % 5) == 0)
                            v.pd.setProgress ((int) pctdone);
                    }

                    fout.flush ();
                    fin.close ();
                    fout.close ();
                }
                catch (IOException e)
                {
                    Log.d (TAG, "fileCopyTask(): DB copy blew up. IOE: " + e.getMessage ());

                    // just in case, attempt to cancel the process in event of cataclysm
                    this.cancel (true);
                    e.printStackTrace ();
                }

                return null;
            }

            // can use UI thread here
            protected void onPostExecute (final Void unused)
            {
                Log.d (TAG, "fileCopyTask():onPostExecute()");

                // set progress bar to 100% when done. 
                v.pd.setProgress (100);
                v.pd.dismiss ();

                // set the state flags to show a succesful completion
                v.taskCancelled = false;
                v.fileCopied = true;

            }// onPostExecute()
        }// fileCopyTask()
    }



///////////////////////////////////////
// myVars.java
//////////////////////////////////////
/**
 * 
 */
package com.test.helloasync;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.DialogInterface;

public class myVars
{
    ProgressDialog pd;
    boolean taskCancelled = false;
    boolean fileCopied = false;
    Object fct;
}

Ответы [ 2 ]

1 голос
/ 12 мая 2011

Я попытался отменить асинхронную задачу, но у меня возникли проблемы при создании нового экземпляра и его выполнении.Предыдущая AsyncTask, казалось, выживала при повороте и начинала обновлять progressDialog, как только была запущена задача NEW .

Думаю, я бы просто позволил Android управлять самой AsyncTask, поскольку она, кажется, хочет, чтобы она работала в фоновом режиме.Итак, в итоге я просто закрыл файл progressDialog для поворота, а затем снова включил его в onResume ().AsyncTask, кажется, просто подхватил, где он остановился.

Я обновлю код выше - надеюсь, это поможет кому-то еще.

0 голосов
/ 10 мая 2011

Обычно вы устанавливаете флаг (например, boolean mIsRunning;), который ваш метод doInBackground() периодически проверяет. Если он очищен, остановите обработку. Если вы хотите отменить задание, установите флаг в false.

...