如何强制主Activity在Android中等待子活动?

时间:2010-05-21 06:13:08

标签: android android-activity blocking wait subactivity

我称之为主要活动的子活动。这个子活动应该从用户那里拿几个数字(我使用编辑文本控件来实现这一点),将它们保存到另一个类中的静态变量并终止。我希望主要活动等待子活动,但两者都只是同时运行。即使这样做也没有用:

     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());

你知道如何强迫主要活动等待吗? Android中不支持Thread.wait()方法(程序抛出错误)。

5 个答案:

答案 0 :(得分:7)

可能是我遗漏了一些东西,但为什么不只是使用startActivityForResultonActivityResult机制?你可以从你的意图得到你的意图的结果。
编辑:顺便说一下,据我所知,如果你从Object.wait()代码运行Activity,如果保持用户界面,则会导致Application not responding错误。

答案 1 :(得分:3)

我同意Nikolay这绝对是安卓的方法。

在子活动使用startActivityForResult中使用setResult启动子活动,以在数据包中添加您需要的所有数字的结果代码和意图。

在您的第一个活动中覆盖onActivityResult并从意图中检索数字。

如果你使用静态变量,这在第一时间似乎更容易,但是它非常不安全,并且在某些情况下这可能不起作用。如果您的程序被发送到后台,您的活动将被保存,但如果手机内存不足,系统将关闭您的程序,用户恢复后,一切看起来就像用户离开它的那一刻,但静态变量将被重新创建为他们的初始化值。

尝试习惯android activity lifecycle的工作方式。使用此方法将减少已用内存和更好的用户体验。

答案 2 :(得分:3)

查看Notepad example,它涵盖了这种情况。正如其他人所说,Android的方式是让你的第一个活动启动你的第二个活动(不是子活动!)并异步监听响应(不是暂停或等待,不需要加入等)。

答案 3 :(得分:2)

嗯......你可以这样做(顺便说一下,没有直接的方式):

有一个单独的类,我们称之为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();
           }
       }
}

答案 4 :(得分:2)

我不是来判断这是不是一个好的模式,但如果你真的需要一个等待子活动的活动,你可以尝试这种方法:

  • 定义一个对象(锁),两个活动在这个对象上同步;这可以(应该)也作为在这两个活动之间交换数据的对象,因此应该被定义为静态
  • 在父活动中,启动异步任务(因为UI主线程不能处于等待状态)
  • 在异步任务中,启动子活动
  • 异步任务等待锁定,直到收到通知
  • 子活动执行它需要的任何内容,并在完成时通知等待的线程

我在我的应用程序中做了类似的事情并且恕我直言有充分的理由(在应用程序启动或恢复时不打扰用户登录屏幕,应用程序尝试重新使用存储在安全位置的凭据,仅在如果它失败了,它会显示这个登录屏幕。所以是的,基本上我的应用程序中的任何活动都可以“暂停”并等待用户在登录活动中提供正确的凭据,登录屏幕完成后应用程序继续正确暂停(在父活动中)。

在代码中它将是这样的:

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);
    }

}