fif*_*fth 53 android synchronization modal-dialog android-activity
这些天我正在研究在Android中模拟模态对话框.我已经google了很多,有很多讨论,但很遗憾没有太多的选择来获得它的模态.这里有一些背景,
对话框,模态对话框和Blockin
对话框/ AlertDialogs:如何在对话框启动时"阻止执行"(.NET风格)
没有直接的方法来获得模态行为,然后我想出了3个可能的解决方案,
1.使用对话框主题的活动,就像这个线程所说的那样,但我仍然无法使主要活动真正等待对话活动返回.主要活动转为停止状态,然后重新启动.
2.构建一个工作线程,并使用线程同步.但是,对于我的应用程序来说,这是一个巨大的重构工作,现在我在主UI线程中有一个主要活动和服务.
3.当存在模态对话框时,在循环内接管事件处理,并在对话框关闭时退出循环.实际上,这是构建一个真正的模态对话框的方式,就像它在Windows中的确切做法一样.我仍然没有这样的原型.
我仍然想用一个以对话为主题的活动模拟它,
1.通过startActivityForResult()启动对话活动
2.从onActivityResult()获取结果
这里有一些来源
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyView v = new MyView(this);
setContentView(v);
}
private final int RESULT_CODE_ALERT = 1;
private boolean mAlertResult = false;
public boolean startAlertDialog() {
Intent it = new Intent(this, DialogActivity.class);
it.putExtra("AlertInfo", "This is an alert");
startActivityForResult(it, RESULT_CODE_ALERT);
// I want to wait right here
return mAlertResult;
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case RESULT_CODE_ALERT:
Bundle ret = data.getExtras();
mAlertResult = ret.getBoolean("AlertResult");
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
startAlertDialog的调用者将阻止执行并期望返回结果.但是当然,startAlertDialog立即返回,当DialogActivity启动时,主要活动进入STOP状态.
所以问题是,如何使主要活动真正等待结果?
谢谢.
小智 65
使用时我得到了一个模态对话框:
setCancelable(false);
Run Code Online (Sandbox Code Playgroud)
在DialogFragment上(不在DialogBuilder上).
Ste*_*han 13
你计划的方式是不可能的.首先,不允许阻止UI线程.您的申请将被终止.其次,需要处理在启动另一个活动时调用的生命周期方法startActivity(在其他活动运行时,您的原始活动将暂停).第三,你可能通过使用startAlertDialog()不是来自UI线程,使用线程同步(如Object.wait())和一些来以某种方式破解它AlertDialog.但是,我强烈建议你不要这样做.它很丑陋,肯定会破坏,而事实并非如此.
重新设计您的方法以捕获这些事件的异步性质.如果你想要一些对话框要求用户进行决定(比如接受或不接受ToS)并根据该决定做特殊操作,请创建一个如下对话框:
AlertDialog dialog = new AlertDialog.Builder(context).setMessage(R.string.someText)
.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// Do stuff if user accepts
}
}).setNegativeButton(android.R.string.cancel, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// Do stuff when user neglects.
}
}).setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
dialog.dismiss();
// Do stuff when cancelled
}
}).create();
dialog.show();
Run Code Online (Sandbox Code Playgroud)
然后有两种方法相应地处理正面或负面反馈(即进行一些操作或完成活动或任何有意义的事情).
Android和iOS的开发人员认为他们是强大而聪明的,足以拒绝Modal Dialog概念(这已经在市场上存在很多年了,之前并没有打扰过任何人),不幸的是我们.
这是我的解决方案,效果很好:
int pressedButtonID;
private final Semaphore dialogSemaphore = new Semaphore(0, true);
final Runnable mMyDialog = new Runnable()
{
public void run()
{
AlertDialog errorDialog = new AlertDialog.Builder( [your activity object here] ).create();
errorDialog.setMessage("My dialog!");
errorDialog.setButton("My Button1", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
pressedButtonID = MY_BUTTON_ID1;
dialogSemaphore.release();
}
});
errorDialog.setButton2("My Button2", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
pressedButtonID = MY_BUTTON_ID2;
dialogSemaphore.release();
}
});
errorDialog.setCancelable(false);
errorDialog.show();
}
};
public int ShowMyModalDialog() //should be called from non-UI thread
{
pressedButtonID = MY_BUTTON_INVALID_ID;
runOnUiThread(mMyDialog);
try
{
dialogSemaphore.acquire();
}
catch (InterruptedException e)
{
}
return pressedButtonID;
}
Run Code Online (Sandbox Code Playgroud)
最后,我得出了一个非常简单的解决方案。
熟悉Win32编程的人可能知道如何实现模式对话框。通常,当出现模式对话框时,它将运行嵌套的消息循环(通过GetMessage / PostMessage)。因此,我尝试以这种传统方式实现自己的模式对话框。
最初,android没有提供可插入ui线程消息循环的接口,或者我没有找到接口。当我查看源代码Looper.loop()时,发现它正是我想要的。但是,MessageQueue / Message仍未提供公共接口。幸运的是,我们在Java中有了反思。基本上,我只是完全复制了Looper.loop()所做的事情,它阻止了工作流并仍然正确处理了事件。我还没有测试过嵌套模式对话框,但是从理论上讲它可以工作。
这是我的源代码,
public class ModalDialog {
private boolean mChoice = false;
private boolean mQuitModal = false;
private Method mMsgQueueNextMethod = null;
private Field mMsgTargetFiled = null;
public ModalDialog() {
}
public void showAlertDialog(Context context, String info) {
if (!prepareModal()) {
return;
}
// build alert dialog
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(info);
builder.setCancelable(false);
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ModalDialog.this.mQuitModal = true;
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
// run in modal mode
doModal();
}
public boolean showConfirmDialog(Context context, String info) {
if (!prepareModal()) {
return false;
}
// reset choice
mChoice = false;
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(info);
builder.setCancelable(false);
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ModalDialog.this.mQuitModal = true;
ModalDialog.this.mChoice = true;
dialog.dismiss();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ModalDialog.this.mQuitModal = true;
ModalDialog.this.mChoice = false;
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
doModal();
return mChoice;
}
private boolean prepareModal() {
Class<?> clsMsgQueue = null;
Class<?> clsMessage = null;
try {
clsMsgQueue = Class.forName("android.os.MessageQueue");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
}
try {
clsMessage = Class.forName("android.os.Message");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
}
try {
mMsgQueueNextMethod = clsMsgQueue.getDeclaredMethod("next", new Class[]{});
} catch (SecurityException e) {
e.printStackTrace();
return false;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return false;
}
mMsgQueueNextMethod.setAccessible(true);
try {
mMsgTargetFiled = clsMessage.getDeclaredField("target");
} catch (SecurityException e) {
e.printStackTrace();
return false;
} catch (NoSuchFieldException e) {
e.printStackTrace();
return false;
}
mMsgTargetFiled.setAccessible(true);
return true;
}
private void doModal() {
mQuitModal = false;
// get message queue associated with main UI thread
MessageQueue queue = Looper.myQueue();
while (!mQuitModal) {
// call queue.next(), might block
Message msg = null;
try {
msg = (Message)mMsgQueueNextMethod.invoke(queue, new Object[]{});
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (null != msg) {
Handler target = null;
try {
target = (Handler)mMsgTargetFiled.get(msg);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (target == null) {
// No target is a magic identifier for the quit message.
mQuitModal = true;
}
target.dispatchMessage(msg);
msg.recycle();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
希望这会有所帮助。
这对我有用:创建一个Activity作为对话框.然后,
将此添加到活动的清单中:
机器人:主题= "@安卓风格/ Theme.Dialog"
将此添加到您的活动的onCreate
setFinishOnTouchOutside(false);
在您的活动中覆盖onBackPressed:
@Override public void onBackPressed(){//阻止"退回"离开此活动}
第一个给对话框看的活动.后两者使其行为类似于模态对话框.
这并不难。
假设您的所有者活动上有一个标志(名为waiting_for_result),每当您的活动恢复时:
public void onResume(){
if (waiting_for_result) {
// Start the dialog Activity
}
}
Run Code Online (Sandbox Code Playgroud)
这保证了所有者活动,除非模式对话框被关闭,否则每当它尝试获得焦点时都会传递到模式对话框活动。
| 归档时间: |
|
| 查看次数: |
90489 次 |
| 最近记录: |