parser - Выполнение асинхронной задачи Android




mp4 parser android (2)

Давайте изменим ваш код на следующее:

class Task1 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName());

        Task2 task = new Task2();
        task.execute();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Log.v ("gaurav", "Log after sleeping");

        return null;
    }
}

class Task2 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName());

        Log.v ("gaurav", "Task 2 Started");
        return null;
    }
}

Теперь LogCat возвращает:

08-07 06:13:44.208    3073-3073/testapplication V/gaurav Thread is : main
08-07 06:13:44.209    3073-3091/testapplication V/gaurav Thread task 1 is : AsyncTask #1
08-07 06:13:49.211    3073-3091/testapplication V/gaurav Log after sleeping
08-07 06:13:49.213    3073-3095/testapplication V/gaurav Thread task 2 is : AsyncTask #2
08-07 06:13:49.213    3073-3095/testapplication V/gaurav Task 2 Started

Как вы можете видеть, Task 2 выполняется после окончания выполнения Task 1 (даже после ожидания в течение 5 секунд). Это означает, что вторая задача не будет запущена, пока первая не будет выполнена.

Зачем? Причина в исходном коде AsyncTask . Пожалуйста, рассмотрите метод execute() :

public synchronized void execute(final Runnable r) {
    mTasks.offer(new Runnable() {
        public void run() {
            try {
                r.run();
            } finally {
                scheduleNext();
            }
        }
    });
    if (mActive == null) {
        scheduleNext();
    }
}

и scheduleNext() метод:

protected synchronized void scheduleNext() {
    if ((mActive = mTasks.poll()) != null) {
        THREAD_POOL_EXECUTOR.execute(mActive);
    }
}

Самое важное ключевое слово в этих методах synchronized что гарантирует, что эти методы будут выполняться только в одном потоке одновременно. Когда вы вызываете метод execute , он предлагает новый Runnable to mTask который является экземпляром класса ArrayDeque<Runnable> который работает как сериализатор различных запросов в разных потоках [подробнее] . Если бы не было выполненного Runnable (т. if (mActive == null) ), было if (mActive == null) scheduleNext() , в противном случае scheduleNext() в блоке finally будет вызвано после (по любой причине) конца текущего исполняемого Runnable , Runnable выполняет все Runnable s в отдельном потоке.

Что не так с выполнением AsyncTask из других потоков? Начиная с Jelly Bean, AsyncTask загружается классом при запуске приложения в потоке пользовательского интерфейса, так что обратные вызовы гарантированно произойдут в потоке пользовательского интерфейса, однако до выпуска Jelly Bean, если другой поток создает AsyncTask обратные вызовы могут не происходит в правильной теме.

Таким образом, реализации AsyncTask должны вызываться из потока пользовательского интерфейса только на платформах до Jelly Bean ( + и + ).

Пояснение: рассмотрите следующий пример, который просто проясняет различия между различными версиями платформы Android:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);

    new Thread() {
        @Override
        public void run() {
            Task1 task = new Task1();
            task.execute();
        }
    }.start();
}

class Task1 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        return null;
    }
}

Он отлично работает на Android 5.1, но вылетает, за исключением Android 2.3:

08-07 12:05:20.736      584-591/github.yaa110.testapplication E/AndroidRuntime FATAL EXCEPTION: Thread-8
    java.lang.ExceptionInInitializerError
            at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)
     Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:121)
            at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
            at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
            at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
            at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)

https://code.i-harness.com

Об этом спрашивали в одном из интервью Android. Меня спросили, можно ли запустить другую асинхронную задачу (пусть это будет Task2) из ​​метода doInBackground () асинхронной задачи 1 (пусть это будет Task1). Я просмотрел документы, в которых говорится следующее:

Экземпляр задачи должен быть создан в потоке пользовательского интерфейса.

execute (Params ...) должен быть вызван в потоке пользовательского интерфейса.

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

При проверке простого демонстрационного приложения я увидел, что это действительно возможно. Некоторый демонстрационный код:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        init();
        Log.v ("gaurav", "Thread is : " + Thread.currentThread().getName());
        Task1 task = new Task1();
        task.execute();
    }

class Task1 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName());

        Task2 task = new Task2();

        task.execute();
        return null;
    }
}

class Task2 extends AsyncTask {
    @Override
    protected Object doInBackground(Object... params) {
        // TODO Auto-generated method stub
        Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName());

        Log.v ("gaurav", "Task 2 started");
        return null;
    }
}

Я получаю следующие журналы, указывающие на успешное выполнение:

> 08-07 09:46:25.564: V/gaurav(2100): Thread is : main 08-07
> 09:46:25.564: V/gaurav(2100): Thread task 1 is : AsyncTask #3 08-07
> 09:46:25.564: V/gaurav(2100): Thread task 2 is : AsyncTask #4 08-07
> 09:46:25.564: V/gaurav(2100): Task 2 started

Я проверил это на устройстве ICS, KK и L, и он отлично работает для всех.

Одна из причин, по которой я мог подумать, заключается в том, что я не переопределяю никакие методы пользовательского интерфейса и не выполняю никаких обновлений пользовательского интерфейса во втором задании, поэтому это не вызывает никаких проблем, но я не уверен. Даже если это так, это нарушает правила потоков, упомянутые в руководстве разработчика.

В качестве ссылки я также проверил эту ссылку: Запустите AsyncTask из другого AsyncTask doInBackground (), но в ответе указано, что нужно запустить вторую задачу с помощью метода runOnUiThread () внутри doInBackground (). Мне нужна помощь в том, что здесь происходит. Благодарю.


public class MainActivity extends Activity {

    private final static String TAG = "ThreadingAsyncTask";
    private ImageView mImageView;
    private ProgressBar mProgressBar;
    private int mDelay = 500;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) findViewById(R.id.imageView);;
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);

        final Button button = (Button) findViewById(R.id.loadButton);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new LoadIconTask().execute(R.drawable.cheetah);
            }
        });
        final Button otherButton = (Button) findViewById(R.id.otherButton);
        otherButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "I'm Working",
                        Toast.LENGTH_SHORT).show();
            }
        });
    }


    class LoadIconTask extends AsyncTask<Integer, Integer, Bitmap> {
        @Override
        protected void onPreExecute() {
            mProgressBar.setVisibility(ProgressBar.VISIBLE);
        }
        @Override
        protected Bitmap doInBackground(Integer... resId) {
            Bitmap tmp = BitmapFactory.decodeResource(getResources(), resId[0]);
            // simulating long-running operation
            for (int i = 1; i < 11; i++) {
                sleep();
                publishProgress(i * 10);
            }
            return tmp;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            mProgressBar.setProgress(values[0]);
        }
        @Override
        protected void onPostExecute(Bitmap result) {
            mProgressBar.setVisibility(ProgressBar.INVISIBLE);
            mImageView.setImageBitmap(result);
        }
        private void sleep() {
            try {
                Thread.sleep(mDelay);
            } catch (InterruptedException e) {
                Log.e(TAG, e.toString());
            }
        }
    }
}




android-asynctask