Как заставить основную активность ждать субактивности в Android? - PullRequest
6 голосов
/ 21 мая 2010

Я вызываю субактивность от основной деятельности. Эта субактивность должна принимать несколько цифр от пользователя (для этого я использую элемент управления «Редактировать текст»), сохранять их в статической переменной в другом классе и завершать. Я хочу, чтобы основная активность ожидала субактивности, но обе они работают одновременно. Даже делать что-то подобное не помогает:

     Thread t = new Thread(new Runnable(){
     public void run(){
     Log.v("==================", "run "+new Date());
     startActivityForResult(new Intent(ctx,myCustomSubactivity.class),1);  
     } });
     Log.v("==================", "calling run "+new Date());
     t.start();      
     try {
        t.join();
    } catch (InterruptedException e) {Log.v("==================", "can't join");}
    Log.v("==================", "back from activity "+new Date());

Вы знаете, как заставить основную деятельность ждать? Метод Thread.wait () не поддерживается в Android (ошибка программы).

Ответы [ 5 ]

7 голосов
/ 21 мая 2010

Может быть, я что-то упускаю, но почему бы просто не использовать механизмы startActivityForResult и onActivityResult? Вы можете получить результат от своей активности из намерения, с которым он был получен.
Изменить: Кстати, насколько я понимаю, если вы будете запускать Object.wait() из Activity кода, если будет удерживать протектора UI, что может привести к ошибке Application not responding.

3 голосов
/ 21 мая 2010

Посмотрите пример Блокнот , он охватывает именно эту ситуацию. И, как уже говорили другие, Android-способ заключается в том, чтобы ваше первое действие запускало ваше второе действие (не подэтап! *

3 голосов
/ 21 мая 2010

Я согласен с Николаем, это определенно андроидный способ сделать это.

Запустите подактивность с startActivityForResult в подоперации, используйте setResult , чтобы добавить код результата и намерение со всеми числами, которые вам нужны в пакете данных.

В вашем первом действии перезаписать onActivityResult и получить числа из намерения.

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

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

2 голосов
/ 25 февраля 2015

Я здесь не для того, чтобы судить, является ли это хорошим шаблоном или нет, но если вам действительно нужно занятие для ожидания подэтапа, вы можете попробовать этот подход:

  • определить объект (блокировку), над которым синхронизируются эти два действия; это может (должно) также работать как объект для обмена данными между этими двумя действиями и поэтому должно быть определено как статическое
  • в родительском действии запустите асинхронную задачу (поскольку основной поток пользовательского интерфейса не может находиться в состоянии ожидания)
  • в асинхронной задаче, запустите ваше вспомогательное действие
  • асинхронная задача ожидает блокировки, пока не получит уведомление
  • дочерняя операция делает все, что ей нужно, и уведомляет ожидающий поток о завершении

Я сделал похожую вещь в своем приложении, и у IMHO была на то веская причина (чтобы не беспокоить пользователя с экраном входа в систему при запуске или возобновлении работы, приложение пытается повторно использовать учетные данные, хранящиеся в защищенном месте и только в в случае неудачи он показывает этот экран входа в систему.Так да, в принципе, любое действие в моем приложении может быть приостановлено и ожидает, пока пользователь не предоставит правильные учетные данные в действии входа в систему, после чего экран входа завершается и приложение продолжает работать именно там, где оно получено. приостановлено (в родительской активности).

В коде это будет примерно так:

ParentActivity:

   public class ParentActivity extends Activity {
    private static final String TAG = ParentActivity.class.getSimpleName();

    public static class Lock {
        private boolean condition;

        public boolean conditionMet() {
            return condition;
        }

        public void setCondition(boolean condition) {
            this.condition = condition;
        }
    }

    public static final Lock LOCK = new Lock();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.parent_layout);

        // do whatever logic you need and anytime you need to stat sub-activity
        new ParentAsyncTask().execute(false);
    }

    private class ParentAsyncTask extends AsyncTask<Boolean, Void, Boolean> {

        @Override
        protected Boolean doInBackground(Boolean... params) {
            // do what you need and if you decide to stop this activity and wait for the sub-activity, do this
            Intent i = new Intent(ParentActivity.this, ChildActivity.class);
            startActivity(i);
            synchronized (LOCK) {
                while (!LOCK.conditionMet()) {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        Log.e(TAG, "Exception when waiting for condition", e);
                        return false;
                    }
                }
            }
            return true;
        }
    }
}

ChildActivity:

public class ChildActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.child_layout);

        // do whatever you need in child activity, but once you want to finish, do this and continue in parent activity
        synchronized (ParentActivity.LOCK) {
            ParentActivity.LOCK.setCondition(true);
            ParentActivity.LOCK.notifyAll();
        }
        finish();

        // if you need the stuff to run in background, use AsyncTask again, just please note that you need to
        // start the async task using executeOnExecutor method as you need more executors (one is already occupied), like this:
        // new ChildAsyncTask().executeOnExecutor(ChildAsyncTask.THREAD_POOL_EXECUTOR, false);
    }

}
2 голосов
/ 21 мая 2010

Ну ... вы можете сделать это так (кстати, нет прямого пути):

Есть класс синглтона, назовем его Monitor:

public class Singleton
{
   private Singleton() { }
   private static Singleton instance = new Singleton();

   public static Singleton getInstance() {
      return instance;
   }
}

public class ParentActivity extends Activity
{
    private void startAndWait()
    {
        Intent i = new Intent();
        // initialize i
        startActivityForResult(i);
        Singleton si = Singleton.getInstance();
        synchronized(si)
        {
             si.wait();
        }
        //do remaining work
    }
}

public class ChildActivity extends Activity
{
       protected void onCreate(Bundle savedInstance)
       {
           //do all the work
           Singleton si = Singleton.getInstance();
           synchronized(si)
           {
             si.notify();
           }
       }
}
...