Android: How to get a modal dialog or similar modal behavior?

后端 未结 11 1909
暗喜
暗喜 2020-12-01 05:17

These days I\'m working on simulating modal dialog in Android. I\'ve googled a lot, there\'s much discussions but sadly there\'s not much options to get it modal. Here\'s so

相关标签:
11条回答
  • 2020-12-01 05:36

    It is not possible the way you planned. First, you are not allowed to block the UI thread. Your application will be terminated. Second, need to handle the lifecycle methods that are called when another activity is started with startActivity (your original acitvity will be paused while the other activity is running). Third, you probably could somehow hack it by using startAlertDialog() not from the UI thread, with thread synchronization (like Object.wait()) and some AlertDialog. However, I strongly encourage you to not do this. It is ugly, will certainly break and it's just not the way things are intended to work.

    Redesign your approach to capture the asynchronous nature of these events. If you want for example some dialog which asks the user for a decsision (like accepting the ToS or not) and do special actions based on that decision create a dialog like this:

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

    Then have two methods handling positive or negative feedback accordingly (i.e. proceeding with some operation or finishing the activity or whatever makes sense).

    0 讨论(0)
  • 2020-12-01 05:37

    One solution is :

    1. Put all code for each selected button into the listener of each button.
    2. alert.show(); must be the last code line in the function calling the Alert. Any code after this line will not wait to close the Alert, but will execute immediately.

    Hope Help!

    0 讨论(0)
  • 2020-12-01 05:44

    As hackbod and others have pointed out, Android deliberately doesn't provide a method for doing nested event loops. I understand the reasons for this, but there are certain situations that require them. In our case we have our own virtual machine running on various platforms and we wanted to port it to Android. Internally there a lot of places where it requires a nested event loop, and it isn't really feasible to rewrite the whole thing just for Android. Anyway, here is a solution (basically taken from How can I do non-blocking events processing on Android?, but I have added a timeout):

    private class IdleHandler implements MessageQueue.IdleHandler
    {
        private Looper _looper;
        private int _timeout;
        protected IdleHandler(Looper looper, int timeout)
        {
            _looper = looper;
            _timeout = timeout;
        }
    
        public boolean queueIdle()
        {
            _uiEventsHandler = new Handler(_looper);
            if (_timeout > 0)
            {
                _uiEventsHandler.postDelayed(_uiEventsTask, _timeout);
            }
            else
            {
                _uiEventsHandler.post(_uiEventsTask);
            }
            return(false);
        }
    };
    
    private boolean _processingEventsf = false;
    private Handler _uiEventsHandler = null;
    
    private Runnable _uiEventsTask = new Runnable()
    {
        public void run() {
        Looper looper = Looper.myLooper();
        looper.quit();
        _uiEventsHandler.removeCallbacks(this);
        _uiEventsHandler = null;
        }
    };
    
    public void processEvents(int timeout)
    {
        if (!_processingEventsf)
        {
            Looper looper = Looper.myLooper();
            looper.myQueue().addIdleHandler(new IdleHandler(looper, timeout));
            _processingEventsf = true;
            try
            {
                looper.loop();
            } catch (RuntimeException re)
            {
                // We get an exception when we try to quit the loop.
            }
            _processingEventsf = false;
         }
    }
    
    0 讨论(0)
  • 2020-12-01 05:45

    Use a BroadcastReceiver that calls the next method required in the activity.

    Dead-end the activity code at dialogFragment.show(fragmentTransaction, TAG); and continue it in onReceive()--i'm not 100% positive but I would lay money that startActivityForResult(); is based on exactly this concept.

    Until that method is invoked from the receiver, the code will stand in wait for user interaction without ANR.

    DialogFragment's onCreateView Method

    private static final String ACTION_CONTINUE = "com.package.name.action_continue";
    
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_dialog, container, false);
            Button ok_button = v.findViewById(R.id.dialog_ok_button);
            ok_button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent i = new Intent();
                    i.setAction(ACTION_CONTINUE);
                    getActivity().getApplicationContext().sendBroadcast(i);
                    dismiss();
                }
            });
    
    
        return v;
    }
    

    This method depends on building a DialogFrament extension class and calling an instance of that class through the activity.

    However...

    Simple, clear, easy and truly modal.

    0 讨论(0)
  • 2020-12-01 05:51

    This works for me: create an Activity as your dialog. Then,

    1. Add this to your manifest for the activity:

      android:theme="@android:style/Theme.Dialog"

    2. Add this to onCreate of your activity

      setFinishOnTouchOutside (false);

    3. Override onBackPressed in your activity:

      @Override public void onBackPressed() { // prevent "back" from leaving this activity }

    The first gives the activity the dialog look. The latter two make it behave like a modal dialog.

    0 讨论(0)
提交回复
热议问题