6

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

     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() 方法(程序抛出错误)。

4

5 回答 5

7

May be I'm missing something but why don't just use startActivityForResult and onActivityResult mechanism? You could get result from you subactivity from intent it was resulted with.
Edit: BTW as far as I understand, if you will run Object.wait() from Activity code if will hold UI tread whitch can result in Application not responding error.

于 2010-05-21T08:50:20.597 回答
3

I agree with Nikolay this is definitely the android way to do this.

Start the subactivity with startActivityForResult in the sub activity use setResult to add an result code and an intent with all the numbers you need in the data bundle.

In your first activity overwrite onActivityResult and retrieve the numbers from the Intent.

If you use the static variable this seems easier in the first moment but it is very insecure and there are some cases this may not work. If your program is send to the background your activities will be saved but if the phone runs low on memory the system will close your program and after the user resumes it everything looks like the moment the user left it but the static variables will be recreated to their initialization value.

Try to get used to the way the android activity lifecycle works. Using this approach will result in fewer used memory and a much better user experience.

于 2010-05-21T09:11:01.247 回答
3

Check out the Notepad example, it covers exactly this situation. And as others have said, the Android way is to have your first activity start up your second activity (not sub-activity!) and asynchronously listen for a response (not pause or wait, no need for joining, etc.).

于 2010-05-21T17:44:13.400 回答
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();
           }
       }
}
于 2010-05-21T06:22:28.060 回答
2

I'm not here to judge if it's a good pattern or not but if you really need an activity to wait for a sub-activity, you can try this approach:

  • define an object (lock) over which the two activities get synchronized; this can (should) also work as the object to exchange data between those two activities and thus should be defined as static
  • in parent activity, start an async task (as the UI main thread cannot be in waiting state)
  • in the async task, start your sub-activity
  • the async task waits on the lock till it gets notified
  • the sub-activity does whatever it needs and notifies the waiting thread when it finishes

I did a similar thing in my app and IMHO had a good reason for this (not to bother a user with login screen upon app start or resume, the app tries to re-use credentials stored in a secured place and only in case it fails, it shows this login screen. So yes, basically any activity in my app can get "paused" and waits till the user provides correct credentials in the login activity upon which the login screen finishes and the app continues exactly where it got paused (in the parent activity).

In the code it would be something like this:

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

}
于 2015-02-25T10:35:03.167 回答