如何强制主活动等待 Android 中的子活动?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2879914/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to force main Acivity to wait for subactivity in Android?
提问by questioner
I am calling a subactivity from main activity. This subactivity should take few numbers from user (i'm using Edit text control to achieve this), save them to static variable in another class and terminate. I want main activity to wait for subactivity but both are just running simultaneously. Even doing sth like that doesn't help:
我正在从主要活动中调用子活动。这个子活动应该从用户那里获取一些数字(我正在使用编辑文本控件来实现这一点),将它们保存到另一个类中的静态变量并终止。我希望主要活动等待子活动,但两者只是同时运行。即使这样做也无济于事:
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());
do you know how to force main activity to wait? Thread.wait() method is not supported in Android(program throws error).
你知道如何强制主要活动等待吗?Android 不支持 Thread.wait() 方法(程序抛出错误)。
采纳答案by Janusz
I agree with Nikolay this is definitely the android way to do this.
我同意 Nikolay 这绝对是做到这一点的 android 方式。
Start the subactivity with startActivityForResultin the sub activity use setResultto add an result code and an intent with all the numbers you need in the data bundle.
在子活动中使用startActivityForResult启动子活动,使用setResult添加结果代码和包含数据包中所需的所有数字的意图。
In your first activity overwrite onActivityResultand retrieve the numbers from the Intent.
在您的第一个活动中覆盖onActivityResult并从 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 lifecycleworks. Using this approach will result in fewer used memory and a much better user experience.
尝试习惯 android活动生命周期的工作方式。使用这种方法将导致更少的内存使用和更好的用户体验。
回答by Nikolay Ivanov
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.
可能是我错过了一些东西,但为什么不只是使用startActivityForResult
和onActivityResult
机制?你可以从你的子活动中从它产生的意图中得到结果。
编辑:顺便说一句,据我所知,如果您Object.wait()
将从Activity
代码中运行,如果将保持 UI 踏板会导致Application not responding
错误。
回答by Josh
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.).
查看记事本示例,它恰好涵盖了这种情况。正如其他人所说,Android 方式是让您的第一个活动启动您的第二个活动(不是子活动!)并异步侦听响应(不是暂停或等待,不需要加入等)。
回答by pepan
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
- 定义两个活动同步的对象(锁);这也可以(应该)作为在这两个活动之间交换数据的对象,因此应该定义为静态
- 在父活动中,启动一个异步任务(因为 UI 主线程不能处于等待状态)
- 在异步任务中,启动您的子活动
- 异步任务等待锁直到它得到通知
- 子活动做它需要的任何事情,并在完成时通知等待线程
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);
}
}
回答by Gaurav Vaish
Well... you can do it like this (btw, there's not straight forward way):
嗯……你可以这样做(顺便说一句,没有直接的方法):
Have a singleton class, let's call it Monitor:
有一个单例类,我们称之为 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();
}
}
}