Как выполнить блокирующее и синхронизированное действие?

#android #android-activity #synchronous

#Android #android-активность #синхронный

Вопрос:

Что ж, пожалуйста, не спрашивайте меня почему, но мне нужно запустить синхронное и блокирующее действие, чтобы поток программ не продолжался до его завершения. Я знаю, как создать синхронный диалог, но как я могу выполнить синхронное действие?

Ниже приведены два подхода, которые я пробовал, но потерпел неудачу:

 // In the 1st activity, start the 2nd activity in the usual way
startActivity(intent);
Looper.loop();        // but pause the program here
// Program continuse running afer Looper.loop() returns
....

// Then, in the second activity's onBackPressed method:
public void onBackPressed() {
    // I was hoping the following quit() will terminate the loop() call in
    // the first activity. But it caused an exception "Main thread not allowed
    // to quit." Understandable.
    new Hanlder().getLooper().quit();
}
  

Я также пытался использовать другой поток для достижения этой цели:

 // In the first activity, start a thread
SecondThread m2ndThread = new SecondThread(this);
Thread th = new Thread(m2ndThread, "Second Thread");
th.run();
synchronized(m2ndThread) {
    m2ndThread.wait();
}

class SecondThread implements Runnable {

    Activity m1stActivity;

    SecondThread(Activity a) {
        m1stActivity = a;
    }

    public void run() {
        Looper.prepare();
        Handler h = new Handler() {
            public void handleMessage() {
                Intent intent = new Intent(m1stActivity, SecondActivity.class);
                m1stActivity.startActivity(intent); // !!!!!!!!!!!!!!
            }
        }
        h.sendEmptyMessage(10); // let it run
        Looper.quit();
    }
}
  

Однако этот подход не работает, потому что, когда я использую 1-е действие для запуска 2-го действия, основной поток уже находится в состоянии ожидания и ничего не делает. Итак, 2-е действие даже не было создано. (Это иронично: вы должны использовать действие для запуска действия, но как вы можете это сделать, когда оно уже находится в состоянии ожидания?)

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

1. Вы не можете просто показать ProgressDialog? Это лишит пользователя возможности взаимодействовать с вашими действиями во время выполнения любой задачи, которую вы выполняете.

2. @dmon, хммм …, ProgressDialog блокируется? Хм… Интересно. Я обязательно попробую. Большое спасибо.

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

4. @dmon, ха-ха-ха, я понял. Но в данном случае это не работает. В любом случае, я изменил спецификацию и придумал довольно неприятный обходной путь.

Ответ №1:

Вы не можете.

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

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

1. отличный ответ, дающий мне некоторое представление об Android. Большое спасибо!

Ответ №2:

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

Объявите флаг в глобальной области видимости этого объекта:

 boolean syncBlock = false;
int ASYNC_ACTIVITY_REQUEST_CODE = 1; // Arbitrary unique int
  

В области видимости объекта, которая запускает новое действие, входят:

 Intent asyncIntent = new Intent(this, AsyncActivity.class);
syncBlock = true;
startActivityForResult(asyncIntent, ASYNC_ACTIVITY_REQUEST_CODE);
while(syncBlock) {}
  

И в в объекте, который запустил действие:

 onActivityResult(int requestCode, int resultCode, Intent data)
{
  switch(requestCode)
  {
    case ASYNC_ACTIVITY_REQUEST_CODE:
    {
      syncBlock = false;
      break;
    }

[...]
}
  

Это грубый взлом, и если вы блокируете в потоке пользовательского интерфейса (например. в вашей ОСНОВНОЙ деятельности) вы блокируете все, включая другие функции пользовательского интерфейса, которые ваши пользователи, вероятно, ожидают отреагировать, но не будут. Это большой nono, и вам следует научиться использовать асинхронный поток, который заставляет приложения работать так, как работает Android. Но если вам абсолютно необходимо…

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

1. Хотя это грубо, это работает! Могу ли я предложить, однако, вместо того, чтобы использовать замкнутый цикл (хотя цикл будет выполняться много раз), вместо этого вы смотрите на CountDownLatch и вызываете await() на защелке после вызова startActivityForResult и countDown() в onActivityResult?

2. @BK: Конечно, цикл while при блокировке синхронизации плохо работает и не совсем безопасен. И действительно, как я упоминал, блокировка в потоке пользовательского интерфейса — плохая идея. Реализация CountDownLatch лучше. Но если вы собираетесь использовать что-то большее, чем грубую блокировку, которую я опубликовал, вам, вероятно, следует пойти немного дальше и использовать асинхронность в своем дизайне, а не удваивать грубый взлом блокировки.

3. Насколько вы правы!! Я поспешил указать на оптимизацию, но вы правы в том, что переход на асинхронность — это правильный путь. Хороший звонок!