Диалоги / AlertDialogs: как "заблокировать выполнение", когда диалог открыт (в стиле.NET)

Исходя из.NET-среды, я сейчас пытаюсь понять, как работают диалоги в Android.

В.NET при вызове MessageBox.Show(...), который создает и показывает всплывающее диалоговое окно. В вызове Show я могу указать, какие кнопки должны быть доступны во всплывающем окне, например:

DialogResult myDialogResult = MessageBox.Show("My text here", "My caption here", MessageBoxButtons.YesNoCancel);

Как вы можете видеть, вызов Show возвращает DialogResult при нажатии кнопки во всплывающем окне, сообщая мне, какая кнопка была нажата. Обратите внимание, что в.NET выполнение останавливается в строке, где выполняется вызов Show (...), поэтому он может возвращать значение при нажатии кнопки.

Если в приведенном выше примере нажать "Нет", myDialogResult будет равен

myDialogResult == DialogResult.No

Поскольку я считаю, что.NET-способ использования / создания всплывающих окон очень прост и интуитивно понятен, мне бы также хотелось, чтобы такой способ создания всплывающих окон в Android.

Итак, вопрос в том, знает ли кто-нибудь, как "остановить выполнение", как с помощью MessageBox.Show, и затем возвращать значение при каждом нажатии кнопки (и диалог исчезает)?

С уважением


РЕДАКТИРОВАТЬ 1: Чтобы быть немного более ясным:

Мне нужно остановить выполнение и подождать, пока пользователь не выберет кнопку, чтобы щелкнуть во всплывающем окне. Код, который следует за вызовом для отображения диалога, зависит от того, какая кнопка была нажата в диалоге.

Вот почему я не могу использовать то, что предлагают Эрих и Алекс, так как написание кода в методах onClick, как предлагается ниже, не будет работать. Причина в том, что я не могу продолжать "нормальное исполнение". Позвольте мне взять пример:

Позвольте мне взять пример:

int nextStep = 0; // this variable will not be reached from within the onClick-methods

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Hello!")
       .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                nextStep = 1; // *** COMPILER ERROR!! ***
            }
        })
        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                nextStep = 2; // *** COMPILER ERROR!! ***
            }
        })
        .create().show();

if (nextStep == 1)
{
    // then do some damage
}
else if (nextStep == 2
    // dont do damage

Если бы я хотел, чтобы выполнение зависело от выбора во всплывающем окне, мне как-то пришлось бы сделать все переменные в "нормальном исполнении" (в данном случае nextStep) доступными в методах onClick, и это звучит для меня как ад,

РЕДАКТИРОВАТЬ 2:

Другим очевидным примером может быть всплывающее окно с вопросом "Хотите продолжить" с опциями "Да" и "Нет".

Если пользователь нажимает "Да", весь метод должен быть прерван, в противном случае он должен продолжить выполнение. Как вы решаете это красиво?

С уважением

20 ответов

Решение

Тед, ты не хочешь этого делать, на самом деле:) Самая большая причина в том, что если ты заблокируешь поток пользовательского интерфейса во время отображения диалога, ты заблокируешь поток, отвечающий за отрисовку и обработку событий вашего диалога. Что означает, что ваш диалог будет не отвечать. Вы также будете вызывать ANR, если пользователю потребуется более нескольких секунд, чтобы щелкнуть диалоговое окно.

Ответ Эриха именно то, что вам нужно. Я знаю, что это не то, что вы хотите, но это не имеет значения. Мы разработали Android, чтобы запретить разработчикам писать синхронные диалоги, чтобы у вас не было особого выбора.

В Android структура отличается от.NET:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Hello!")
       .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // Handle Ok
           }
       })
       .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // Handle Cancel
           }
       })
       .create();

Вы получите диалог с двумя кнопками, и вы будете обрабатывать нажатия кнопок с помощью обратных вызовов. Возможно, вам удастся написать некоторый код, чтобы синтаксис был более похож на.NET, но жизненный цикл диалога довольно тесно связан с ActivityТаким образом, в конце концов, это может быть больше проблем, чем стоит. Дополнительные ссылки на диалоги здесь.

Упрощенная версия ответа Даниила выше. Эта функция получает "да" или "нет" от пользователя в диалоговом окне с предупреждением, но ее можно легко изменить, чтобы получить другой ввод.

private boolean mResult;
public boolean getYesNoWithExecutionStop(String title, String message, Context context) {
    // make a handler that throws a runtime exception when a message is received
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message mesg) {
            throw new RuntimeException();
        } 
    };

    // make a text input dialog and show it
    AlertDialog.Builder alert = new AlertDialog.Builder(context);
    alert.setTitle(title);
    alert.setMessage(message);
    alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            mResult = true;
            handler.sendMessage(handler.obtainMessage());
        }
    });
    alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            mResult = false;
            handler.sendMessage(handler.obtainMessage());
        }
    });
    alert.show();

    // loop till a runtime exception is triggered.
    try { Looper.loop(); }
    catch(RuntimeException e2) {}

    return mResult;
}

В Android диалоги асинхронны, поэтому вам придется структурировать код немного по-другому.

Итак, в C# ваша логика запускает что-то вроде этого в псевдокоде:

void doSomeStuff() {
    int result = showDialog("Pick Yes or No");

    if (result == YES) {
        //do stuff for yes
    }
    else if (result == NO) {
        //do stuff for no
    }

    //finish off here
}

Для Android это должно быть менее аккуратно. Думайте об этом так. У вас будет OnClickListener как это:

public void onClick(DialogInterface dialog, int whichButton) {
   if (whichButton == BUTTON_POSITIVE) {
      doOptionYes();
   }
   else if (whichButton == BUTTON_NEGATIVE) {
      doOptionNo();
   }
}

Который затем поддерживается следующими методами:

void doOptionYes() {
    //do stuff for yes
    endThings();
}

void doOptionNo() {
    //do stuff for no
    endThings();
}

void endThings() {
    //clean up here
}

Итак, что было одним методом, теперь четыре. Боюсь, это может показаться не таким аккуратным, но вот как это работает.

PasswordDialog dlg = new PasswordDialog(this);

if(dlg.showDialog() == DialogResult.OK)

{

    //blabla, anything your self

}


public class PasswordDialog extends Dialog
{
    int dialogResult;
    Handler mHandler ;

    public PasswordDialog(Activity context, String mailName, boolean retry)
    {

        super(context);
        setOwnerActivity(context);
        onCreate();
        TextView promptLbl = (TextView) findViewById(R.id.promptLbl);
        promptLbl.setText("Input password/n" + mailName);
    }
    public int getDialogResult()
    {
        return dialogResult;
    }
    public void setDialogResult(int dialogResult)
    {
        this.dialogResult = dialogResult;
    }
    /** Called when the activity is first created. */

    public void onCreate() {
        setContentView(R.layout.password_dialog);
        findViewById(R.id.cancelBtn).setOnClickListener(new android.view.View.OnClickListener() {

            @Override
            public void onClick(View paramView)
            {
                endDialog(DialogResult.CANCEL);
            }
            });
        findViewById(R.id.okBtn).setOnClickListener(new android.view.View.OnClickListener() {

            @Override
            public void onClick(View paramView)
            {
                endDialog(DialogResult.OK);
            }
            });
        }

    public void endDialog(int result)
    {
        dismiss();
        setDialogResult(result);
        Message m = mHandler.obtainMessage();
        mHandler.sendMessage(m);
    }

    public int showDialog()
    {
        mHandler = new Handler() {
            @Override
              public void handleMessage(Message mesg) {
                  // process incoming messages here
                //super.handleMessage(msg);
                throw new RuntimeException();
              }
          };
        super.show();
        try {
            Looper.getMainLooper().loop();
        }
        catch(RuntimeException e2)
        {
        }
        return dialogResult;
    }

}

Разработчики Android и iOS решили, что они достаточно мощные и умные, чтобы отказаться от концепции Modal Dialog (которая была на рынке уже много-много лет и раньше никого не беспокоила), к сожалению для нас. Я считаю, что есть обходной путь для Android - так как вы можете показать диалог из не-пользовательского потока, используя класс Runnable, должен быть способ ожидания в этом потоке (не-пользовательский интерфейс), пока диалог не будет завершен.

Редактировать: вот мое решение, оно прекрасно работает:

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

При попытке оптимизировать память и производительность диалоги в Android являются асинхронными (по этой причине они также управляются). Исходя из мира Windows, вы привыкли к модальным диалогам. Диалоги Android являются модальными, но больше похожи на немодальные, когда дело доходит до исполнения. Выполнение не останавливается после отображения диалогового окна.

Лучшее описание Dialogs в Android я видел в "Pro Android" http://www.apress.com/book/view/1430215968

Это не идеальное объяснение, но оно должно помочь вам разобраться в различиях между диалогами в Windows и Android. В Windows вы хотите сделать A, задать вопрос с помощью диалогового окна, а затем сделать B или C. В android design A со всем кодом, необходимым для B и C в onClick() OnClickListener(s) для диалога, Затем сделайте A и запустите диалог. Вы сделали с A! Когда пользователь нажимает кнопку B или C будет выполнен.

Windows
-------
A code
launch dialog
user picks B or C
B or C code
done!

Android
-------
OnClick for B code (does not get executed yet)
OnClick for C code (does not get executed yet)
A code
launch dialog
done!
user picks B or C

Тед, как вы, наверное, узнали, к сожалению, вы не можете сделать это на Android. Диалоги являются модальными, но асинхронными, и это определенно нарушит последовательность, которую вы пытаетесь установить, как вы сделали бы в.NET (или Windows в этом отношении). Вы должны будете перевернуть свой код и сломать некоторую логику, которой было бы очень легко следовать на основе вашего примера.

Другой очень простой пример - сохранение данных в файле, только чтобы узнать, что файл уже существует и просит перезаписать его или нет. Вместо отображения диалога и наличия оператора if для воздействия на результат (Да / Нет), вам придется использовать обратные вызовы (называемые слушателями в Java) и разделить вашу логику на несколько функций.

В Windows, когда отображается диалоговое окно, насос сообщений продолжает работать в фоновом режиме (удерживается только текущее обрабатываемое сообщение), и это прекрасно работает. Это позволяет пользователям перемещать ваше приложение и позволяет перекрашивать, когда вы, например, отображаете диалоговое окно. WinMo поддерживает синхронные модальные диалоги, как и BlackBerry, но не Android.

Самое чистое и простое решение - использовать собственный интерфейс слушателя, чтобы при нажатии пользователем кнопки "ОК" ваш слушатель вызывался с возвращаемым значением. Этот метод не делает ничего особенного или сложного и уважает принципы Android.

Определите ваш интерфейс слушателя следующим образом:

public interface EditListener
/* Used to get an integer return value from a dialog
 * 
 */
{
 void returnValue(int value); 
}

Для своего приложения я создал класс EditValue, который использует AlertDialog и который я вызываю всякий раз, когда хочу изменить целочисленное значение. Обратите внимание, как интерфейс EditListener передается в качестве аргумента этому коду. Когда пользователь нажимает кнопку ОК, значение будет возвращено в ваш код вызова с помощью метода EditListener:

public final class EditValue
/* Used to edit a value using an alert dialog
 * The edited value is returned via the returnValue method of the supplied EditListener             interface
 * Could be modified with different constructors to edit double/float etc
 */
{
 public EditValue(final Activity parent, int value, String title, String message,
                  final EditListener editListener)
 {AlertDialog.Builder alert= new AlertDialog.Builder(parent);
  if(title==null) title= message;
  else if(message==null) message= title;
  if(title!=null) alert.setTitle(title);
  if(message!=null) alert.setMessage(message);

  // Set an EditText view to get user input 
  final EditText input = new EditText(parent);
  input.setText(String.valueOf(value));
  input.setInputType(InputType.TYPE_CLASS_NUMBER);
  alert.setView(input);

  alert.setPositiveButton("OK",new DialogInterface.OnClickListener()
  {public void onClick(DialogInterface dialog, int which)
   {try
    {int newValue= Integer.valueOf(input.getText().toString());
     editListener.returnValue(newValue);
     dialog.dismiss();
    }catch(NumberFormatException err) { }
   }
  });

  alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
  {public void onClick(DialogInterface dialog, int which)
   {dialog.dismiss();
    }
  });

  alert.show();
 }
}

Наконец, когда вы используете EditValue, вам нужно объявить свой EditListener, и теперь вы можете получить доступ к возвращаемому значению и делать то, что вы хотите сделать:

 new EditValue(main,AnchorManager.anchorageLimit,
               main.res.getString(R.string.config_anchorage_limit),null,
               new EditListener()
 {public void returnValue(int value) {AnchorManager.anchorageLimit= value;}
  }
 );

Переписывание:

Существуют радикальные различия между мобильной и настольной средой, а также между тем, как приложения разрабатывались несколько лет назад и сегодня:

а) мобильные устройства должны экономить энергию. Часть ценности, которую они предлагают. Поэтому вам нужно экономить ресурсы. Нити являются дорогим ресурсом. Остановка продвижения потока является недопустимой тратой этого ресурса.

б) В наше время пользователь гораздо более требователен. Чтобы помочь им, мы полагаем, что он заслуживает полноценного процессора и минимальных затрат энергии. Его приложение не одиноко на устройстве, есть неизвестное количество других приложений, работающих одновременно, и ваше приложение не обязательно является самым срочным.

c) блокировки на системном уровне не являются опцией: мобильное устройство работает с рядом событий и служб в фоновом режиме, и это не правильно, поскольку любое из них может быть заблокировано приложением.

Подумайте о том, что пользователь получает телефонный звонок, пока работает ваша "системная блокировка"...

Исходя из вышеизложенных фактов, ответом на предложенный вопрос являются:

  • Есть ли жизнеспособный способ построить диалог, который блокирует основной поток до получения ответа от пользователя?

Нет. Обходные пути ухудшают пользовательский опыт, и может быть ошибкой обвинять саму систему. Это несправедливо и наказывает платформу и всех ее разработчиков.

  • Есть ли способ заблокировать всю систему с помощью диалога?

Нет. Это строго запрещено на платформе. Ни одно приложение не может вмешиваться в работу системы или других приложений.

  • Мне нужно провести рефакторинг своего приложения или переосмыслить свой способ программирования в соответствии с архитектурой мобильной системы Android.

Да. Включая этот аспект.

Я новичок в мире Android/Java и с удивлением обнаружил здесь (если я не понимаю, что я читаю), что модальные диалоги не работают. По некоторым неясным для меня причинам в данный момент я получил этот "ShowMessage" эквивалент с кнопкой "ok", которая работает на моем планшете очень модально.

Из моего модуля TDialogs.java:

class DialogMes 
{

  AlertDialog alertDialog ;
  private final Message NO_HANDLER = null;
  public DialogMes(Activity parent,String aTitle, String mes)
  {
    alertDialog = new AlertDialog.Builder(parent).create();
    alertDialog.setTitle(aTitle);    
    alertDialog.setMessage(mes) ;  
    alertDialog.setButton("OK",NO_HANDLER) ;    
    alertDialog.show() ; 
  } 
}

Вот часть кода теста:

public class TestDialogsActivity extends Activity implements DlgConfirmEvent
{

   @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Button btShowMessage = (Button) findViewById(R.id.btShowMessage);
    btShowMessage.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) 
      {
        DialogMes dlgMes = new DialogMes( TestDialogsActivity.this,"Message","life is good") ;                
      }  
    }); 

Я также реализовал модальное диалоговое окно "Да / Нет", следуя интерфейсному подходу, предложенному выше JohnnyBeGood, и он тоже работает довольно хорошо.

Исправление:

Мой ответ не имеет отношения к вопросу, который я неправильно понял. По какой-то причине я интерпретировал г-на Ромена Гая "вы не хотите этого делать" как модальные диалоги "нет". Я должен был прочитать: "Вы не хотите делать это... таким образом".

Приношу извинения.

Вы устанавливаете на слушателей кнопки onclick для вас. распусти диалог и сделай свое действие. Не нужно ничего останавливать

protected Dialog onCreateDialog(int id) {
  return new AlertDialog.Builder(this).setTitle(R.string.no_connection).setIcon(android.R.drawable.ic_dialog_alert).setView(textEntryView).setPositiveButton(R.string.exit, new DialogInterface.OnClickListener() 
{

   public void onClick(DialogInterface dialog, int whichButton) {

  // Here goes what you want to do
  }

})
}

позвонить - ex - showDialog(DIALOG_ERROR_PREF);

Подробнее http://developer.android.com/guide/topics/ui/dialogs.html

Позвольте мне в качестве благодарности сообществу Stackru поделиться с вами чем-нибудь приятным, где я использовал приведенный выше пример в коде Android для HTTP-вызовов, который теперь превращает МОДАЛЬНЫЙ вместо обычного дополнительного потока и сложности слияния потоков с помощью немного своеобразной резьбы. (Это работает в нашем приложении прямо сейчас - 15 октября 2020 г.)

public JSONArray genericHttpModal(Context context, final String url, final JSONObject request) {

    this.url = url;    
    genericHttpRequestQueue = Volley.newRequestQueue(context);      
    class MyJsonReturn {
        JSONArray returnJsonArray;

        public void set(JSONArray i) {
            returnJsonArray = i;
        }

        public void set(String i) {
            try {
                returnJsonArray.put(0, i);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        public JSONArray get() {
            return returnJsonArray;
        }
    }

    final MyJsonReturn mymy = new MyJsonReturn();

    // Positive Response / HTTP OK.
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            throw new RuntimeException();
        }
    };

    final Response.Listener responseListener = new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            try {
                mymy.set(new JSONArray(response));
            } catch (JSONException e) {
                mymy.set("[{\"JSONException:\"" + e.getMessage() + "\"}]");
            }
            handler.sendMessage(handler.obtainMessage());
        }
    };

    // Negative Response / HTTP NOT OK
    final Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            result = "fail";

            try {
                mymy.set(new JSONArray("[{\"JSONException:\"" + result + "\"}]"));
            } catch (JSONException e) {
                mymy.set("[{\"JSONException:\"" + e.getMessage() + "\"}]");
            }
            handler.sendMessage(handler.obtainMessage());
        }
    };


    final StringRequest httpRequest = new StringRequest(Request.Method.POST, URL_POINTER + url,
            responseListener,
            errorListener) {

        // Here the mRequestQueue handler will get the parameters for this request here.
        // Ref: https://stackru.com/questions/33573803/how-to-send-a-post-request-using-volley-with-string-body#33578202
        // Ref: Multi Threaded solution 14 Oct 2020 (David Svarrer) : https://stackru.com/questions/2028697/dialogs-alertdialogs-how-to-block-execution-while-dialog-is-up-net-style (This stackru here)
        @Override
        protected java.util.Map<String, String> getParams() throws AuthFailureError {
            return jsonObjectToMap(request);
        }
    };
    httpRequest.setShouldCache(false); // Elijah: Could work on dropping the cache !!!
    genericHttpRequestQueue.add(httpRequest);    

    try {
        Looper.loop();
    } catch (RuntimeException re) {
    }
    return mymy.get();
}

Попробуйте это в потоке (не в UI-потоке):

final CountDownLatch latch = new CountDownLatch(1);
handler.post(new Runnable() {
  @Override
  public void run() {
    OnClickListener okListener = new OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
      latch.countDown();
    }
  };

  AlertDialog dialog = new AlertDialog.Builder(context).setTitle(title)
    .setMessage(msg).setPositiveButton("OK", okListener).create();
  dialog.show();
}
});
try {
  latch.await();
} catch (InterruptedException e) {
  e.printStackTrace();
}
UserSelect =null

AlertDialog.Builder builder = new Builder(ImonaAndroidApp.LoginScreen);
            builder.setMessage("you message");
            builder.setPositiveButton("OK", new OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    UserSelect = true ;

                }
            });

            builder.setNegativeButton("Cancel", new OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    UserSelect = false ;

                }
            });
           // in UI thread
        builder.show();             
        // wait until the user select
            while(UserSelect ==null);

Ху! Черт, я целый день боролся за это. Каким-то образом я нашел обходной путь, хотя я бы не рекомендовал его. Для этого вам придется использовать Handler.
вызвать функцию, чтобы получить

      boolean result =  getDialogBack(this);
Log.d(TAG, "onCreate: "+result);   

В getDialogBackнаписать диалог и код обработчика, чтобы сделать его синхронным

      public int getDialogBack(Context context,int i) {
        final Handler handler = new Handler(Looper.getMainLooper()) {

            @Override
            public void handleMessage(Message mesg) {
                throw new RuntimeException();
            }
        };

        AlertDialog.Builder alert = new AlertDialog.Builder(context);
        alert.setTitle("Title");
        alert.setMessage("Message");
        alert.setPositiveButton("Want to print next", new
                DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        handler.sendMessage(handler.obtainMessage());
                    }
                });
        alert.setNegativeButton("Return False", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                handler.sendMessage(handler.obtainMessage());
            }
        });
        alert.show();

        try {
            Looper.loop();
        } catch (RuntimeException e) {
        }

        return true;
    }

Просто чтобы ответить на ваш вопрос... кстати, я извиняюсь на 9 месяцев:D... есть "обходной путь" 4 такого рода проблем. т.е.

new AlertDialog.Builder(some_class.this).setTitle("bla").setMessage("bla bla").show();
wait();

просто добавьте wait ();

и они в OnClickListener снова запускают класс с помощью notify () примерно так

@Override
    public void onClick(DialogInterface dialog, int item) {
        Toast.makeText(getApplicationContext(), "test", Toast.LENGTH_LONG).show();
        **notify**();
        dialog.cancel();
    }

тот же обходной путь идет 4 тоста и другие асинхронные вызовы в Android

Я использую Xamarin.Android (MonoDroid), и у меня есть требования для разработки окна подтверждения блокировки пользовательского интерфейса. Я не собираюсь спорить с клиентом, потому что вижу веские причины, почему они этого хотят ( подробности здесь), поэтому мне нужно это реализовать. Я пробовал @Daniel и @MindSpiker выше, но они не работали на MonoForAndroid, в момент отправки сообщения между потоками приложение зависало. Я предполагаю, что это как-то связано с картированием Xamarin.

Я закончил тем, что создал отдельный поток из потока пользовательского интерфейса, а затем заблокировал его и ждал ответа пользователя следующим образом:

// (since the controllers code is shared cross-platforms)
protected void RunConfirmAction(Action runnableAction)
{
    if (runnableAction != null)
    {
        if (Core.Platform.IsAndroid)
        {
            var confirmThread = new Thread(() => runnableAction());
            confirmThread.Start();
        }
        else
        {
            runnableAction();
        }
    }
}

// The call to the logout method has now changed like this:
RunConfirmAction(Logout);

// the implemtation of the MessageBox waiting is like this:
public DialogResult MessageBoxShow(string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
{
    if (_CurrentContext != null && _CurrentContext.Screen != null && MainForm.MainActivity != null)
    {
        Action<bool> callback = OnConfirmCallBack;
        _IsCurrentlyInConfirmProcess = true;
        Action messageBoxDelegate = () => MessageBox.Show(((Activity)MainForm.MainActivity), callback, message, caption, buttons);
        RunOnMainUiThread(messageBoxDelegate);
        while (_IsCurrentlyInConfirmProcess)
        {
            Thread.Sleep(1000);
        }               
    }
    else
    {
        LogHandler.LogError("Trying to display a Message box with no activity in the CurrentContext. Message was: " + message);
    }
    return _ConfirmBoxResult ? DialogResult.OK : DialogResult.No;

}

private void OnConfirmCallBack(bool confirmResult)
{
    _ConfirmBoxResult = confirmResult;
    _IsCurrentlyInConfirmProcess = false;
}

private bool _ConfirmBoxResult = false;
private bool _IsCurrentlyInConfirmProcess = false;

Полную информацию о том, как это сделать, можно найти в моем блоге здесь

Это самый простой способ:

new AlertDialog.Builder(this).setTitle("title").setMessage("message").create().show();
Другие вопросы по тегам