Серия AsyncTask не запускается для выполнения мгновенно

#android #multithreading #android-asynctask

#Android #многопоточность #android-asynctask

Вопрос:

Мой MainActivity имеет 2 вида: TextView и кнопку. При нажатии кнопки я запускаю AsyncTask, который дополнительно создает 10 новых асинхронных задач для сетевых операций. Каждое создание новой задачи задерживается на 1 секунду. Код:

 public class MainActivity extends ActionBarActivity 
{
    TextView tv;
    Button t;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.textView1);
        t = (Button) findViewById(R.id.toggleButton1);      
        t.setOnClickListener(new OnClickListener() 
        {           
            @Override
            public void onClick(View v) 
            {
                getData();
            }
        });
    }

    void getData()
    {
        SuperNetworkAsyncTask s = new SuperNetworkAsyncTask();
        s.execute("");
    }


    private class SuperNetworkAsyncTask extends AsyncTask<String, Void, String>
    {
        @Override
        protected String doInBackground(String... urls) 
        {
            for(int i=0;i<10;i  )
            {
                {
                    nTask = new NetworkAsyncTask();
                    nTask.execute("");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }               
            return "";

        }

        @Override
        protected void onPostExecute(String result)
        {

        }                       
    }   


    private class NetworkAsyncTask extends AsyncTask<String, Void, String>
    {
        @Override
        protected String doInBackground(String... urls) 
        {
            return String.valueOf(System.currentTimeMillis());
        }

        @Override
        protected void onPostExecute(String result)
        {
            tv.setText(result);
        }                       
    }

}
  

Я ожидал, что в тот момент, когда будет вызван первый метод выполнения NetworkAsyncTask, он начнет выполнение. Но когда я запускаю его, я не нахожу, чтобы какая-либо NetworkAsyncTask начинала свое выполнение, пока управление не выйдет из SuperNetworkAsyncTask. Есть ли какой-либо способ ускорить выполнение потока NetworkAsyncTask, как только вызывается метод execute?

Некоторые пояснения:

Почему NetworkAsyncTask создается SuperNetworkAsyncTask? Потому что, если я создаю NetworkAsyncTask в основном потоке, мой пользовательский интерфейс зависает на некоторое время.

Зачем создавать объект 10? Цель NetworkAsyncTask — считывать данные с сервера с интервалом в 1 секунду в течение n секунд, здесь n = 10.

Часть 2: Обновления после выполнения некоторых тестов.

Наблюдение 1: как коллега Брайан поделился способом избежать создания асинхронных задач вложенным способом, я попробовал его код:

 void getData() {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i <= 10; i  ) {

                nTask = new NetworkAsyncTask();
                nTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    new Thread(runnable).start();
}
  

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

Наблюдение 2:

With java.lang.Thread, I experimented to make sure that 1) The threads should be executed right away when run() called. 2) The next task will be created only after previous task is finished.

Code:

 public static void main(String[] args) {
    myThread m;
    for (int i=0;i<10;i  )
    {
        m=new myThread(String.valueOf(i));
        m.start();
        synchronized (m) 
        {
            try {
                m.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }           
    }
}

public class myThread extends Thread
{

    public String name = "";

    public myThread(String n)
    {
        name = n;
    }

    public void run()
    {
        synchronized (this) 
        {           
            System.out.println(" Thread Name = "   name);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {          
                e.printStackTrace();
            }           
            notifyAll();
        }   
    }
}
  

Вывод:

 Thread Name = 0
 Thread Name = 1
 Thread Name = 2
 Thread Name = 3
 Thread Name = 4
 Thread Name = 5
 Thread Name = 6
 Thread Name = 7
 Thread Name = 8
 Thread Name = 9
  

Исходя из этого, я обновил свою NetworkAsyncTask amp; SuperNetworkAsyncTask как:

 private class NetworkAsyncTask extends AsyncTask<String, Void, String>
{
    @Override
    protected String doInBackground(String... urls) 
    {
        synchronized (this) 
        {
            return String.valueOf(System.currentTimeMillis());              
        }

    }

    @Override
    protected void onPostExecute(String result)
    {
        synchronized (this) 
        {
            tv.setText(result);
            notifyAll();
        }
    }
}

private class SuperNetworkAsyncTask extends AsyncTask<String, Void, String>
{
    @Override
    protected String doInBackground(String... urls) 
    {
        for(int i=0;i<10;i  )
        {
            nTask = new NetworkAsyncTask();
            nTask.execute(url);
            synchronized (nTask) 
            {
                try {
                    nTask.wait();
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }                   
            }

        }               
        return "";

    }

    @Override
    protected void onPostExecute(String result)
    {

    }                       
}
  

С этим кодом wait () продолжает ждать бесконечно.

Наконец я заменил:

 nTask.execute(url);
  

с

 nTask.executeOnExecutor(THREAD_POOL_EXECUTOR, "");
  

Это сработало так, как ожидалось.

Комментарии:

1. Какой смысл запускать серию асинхронных задач из другой асинхронной задачи? Вы также можете сделать это из потока пользовательского интерфейса.

2. Используйте executeOnExecutor вместо execute . [Отсюда]( developer.android.com/reference/android/os /… , Параметры…)).

3. AsyncTask внутри AsyncTask не является хорошим выбором. Вызывая множественный поток, порядок выполнения, параллельный или последовательный, зависит от версии API. executeOnExecutor может обрабатывать несколько потоков, запущенных одновременно.

4. что вы пытаетесь сделать за эти 10 AsyncTask секунд?

5. Почему NetworkAsyncTask создается SuperNetworkAsyncTask? Потому что, если я создаю NetworkAsyncTask в основном потоке, мой пользовательский интерфейс зависает на некоторое время.

Ответ №1:

Пользовательский интерфейс будет обновляться только в onPostExecute() . Смотрите Заметки по AsyncTask Нажмите здесь! И старайтесь избегать 10 AysncTasks, это не имеет никакого смысла.

Ответ №2:

Вам не нужно использовать «супер асинхронную задачу», используйте runnable, а затем параллельно создавайте новые асинхронные задачи

 void getData() {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i <= 10; i  ) {

                nTask = new NetworkAsyncTask();
                nTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    new Thread(runnable).start();
}
  

Post honeycomb вы можете указать для параллельного выполнения асинхронных задач

Комментарии:

1. Брайан, Егор, pr38y: я только что попробовал этот код Брайана, а также пробовал это раньше. Каждый раз, когда я зависаю на экране, я думаю, на 20 секунд. Я знаю, что этого не должно произойти, поскольку одно из моих других приложений работает хорошо, когда я создаю асинхронные задачи из потока пользовательского интерфейса. Я тоже удивлен. Я использую 4.2.2.

Ответ №3:

An AsyncTask следует запускать в потоке пользовательского интерфейса, а не в том, на котором doInBackground выполняется. Вы можете вызывать publishProgress после каждого сна и порождать каждый AsyncTask из результирующих вызовов onProgressUpdate , которые выполняются в потоке пользовательского интерфейса.