Вопрос

Я разрабатываю сетевое приложение, которое ориентировано на группу. Дело в том, что когда я собираюсь присоединиться к группе, она сначала проверяет, безопасна ли группа, и если да, то она просит пользователя и пароль. Получение групповой безопасности может занять пару секунд, поэтому я неную новую нить для всего процесса. Я хотел бы всплыть диалог в случае, если группа требует безопасности. Я думаю, что может быть связано с фоновыми нитями, они могут не иметь в состоянии всплывать диалоги ... Но дело в том, что мне нужно проверить групповую безопасность в фоновом потоке, потому что это займет немного времени.

Надеюсь, что кто-то может придумать решение или любой способ запросить пользователь / пройти только тогда, когда группа безопасна. Вот фон фона:

public void run() {

 secInf = mGroupId.getSecurityInformation();
 if (secInf.getAdmissionLevel() == CreateGroupDialog.PRIVATE_KEY_ACCESS) {
  showUserPasswordDialog();
 } else {
  mService.joinGroup(mGroupId);
  // Notifies handler to dismiss ProgresDialog and start activity
  mHandler.sendMessage(Message.obtain(mHandler,
      GroupsActivity.JOIN_SUCCESSFUL));
 }

Где ShowUserPasswordDialog делает (мадейтивность - это активность, которая породила эту нить):

 private void showUserPasswordDialog() {
  AlertDialog dialog;
  // add this to your code
  // This example shows how to add a custom layout to an AlertDialog
  LayoutInflater factory = LayoutInflater.from(mActivity);
  final View textEntryView = factory.inflate(
    R.layout.alert_dialog_text_entry, null);

  AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
  builder.setIcon(R.drawable.alert_dialog_icon);
  builder.setTitle(R.string.ask_user_password);
  builder.setView(textEntryView);
  builder.setPositiveButton(R.string.ok_text,
    new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int whichButton) {
      String userName = ((EditText) mActivity
        .findViewById(R.id.username_edit_alert_dialog))
        .getText().toString();
      String password = ((EditText) mActivity
        .findViewById(R.id.password_edit_alert_dialog))
        .getText().toString();
      Credentials cred = new CredentialsL1(userName, password);

      mSmeppService.joinGroup(mGroupId, cred);

      mHandler.sendMessage(Message.obtain(mHandler,
        GroupsActivity.JOIN_SUCCESSFUL));
    });
  builder.setNegativeButton(R.string.cancel_text,
    new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int whichButton) {
      dialog.cancel();
      mHandler.sendMessage(Message.obtain(mHandler,
        GroupsActivity.DISMISS_PROGRESS_DIALOG));
     }
    });

  dialog = builder.create();

  /* I found this somewhere, but didn't work either */
  // Window window = dialog.getWindow();
  // WindowManager.LayoutParams lp = window.getAttributes();
  // lp.token = textEntryView.getWindowToken();
  // lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
  // window.setAttributes(lp);
  // window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

  dialog.show();

 }

Я получаю это исключение:

12-13 19:18:31.823: ERROR/AndroidRuntime(1702): FATAL EXCEPTION: Thread-38
12-13 19:18:31.823: ERROR/AndroidRuntime(1702): android.view.InflateException: Binary XML file line #17: Error inflating class android.widget.EditText
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.view.LayoutInflater.createView(LayoutInflater.java:513)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at org.pfc.threads.GroupJoinerThread.showUserPasswordDialog(GroupJoinerThread.java:76)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at org.pfc.threads.GroupJoinerThread.run(GroupJoinerThread.java:52)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702): Caused by: java.lang.reflect.InvocationTargetException
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.widget.EditText.<init>(EditText.java:51)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at java.lang.reflect.Constructor.constructNative(Native Method)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at java.lang.reflect.Constructor.newInstance(Constructor.java:446)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.view.LayoutInflater.createView(LayoutInflater.java:500)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     ... 8 more
12-13 19:18:31.823: ERROR/AndroidRuntime(1702): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.os.Handler.<init>(Handler.java:121)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.text.method.MetaKeyKeyListener$MetaKeyDropbackHandler.<init>(MetaKeyKeyListener.java:605)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.text.method.MetaKeyKeyListener.<init>(MetaKeyKeyListener.java:96)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.text.method.BaseKeyListener.<init>(BaseKeyListener.java:25)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.text.method.TextKeyListener.<init>(TextKeyListener.java:66)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.text.method.TextKeyListener.getInstance(TextKeyListener.java:83)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.widget.TextView.<init>(TextView.java:806)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     at android.widget.EditText.<init>(EditText.java:55)
12-13 19:18:31.823: ERROR/AndroidRuntime(1702):     ... 12 more

Файл макета XML:

   <EditText
       android:id="@+id/username_edit_alert_dialog"
       android:enabled="false"
       android:layout_height="wrap_content"
       android:layout_width="fill_parent"
       android:layout_marginLeft="20dip"
       android:layout_marginRight="20dip"
       android:scrollHorizontally="true"
       android:autoText="false"
       android:capitalize="none"
       android:gravity="fill_horizontal"
       android:textAppearance="?android:attr/textAppearanceMedium" />
  <!-- Password -->
   <TextView
       android:id="@+id/password_view"
       android:layout_height="wrap_content"
       android:layout_width="wrap_content"
       android:layout_marginLeft="20dip"
       android:layout_marginRight="20dip"
       android:text="@string/password_view_text"
       android:gravity="left"
       android:textAppearance="?android:attr/textAppearanceMedium" />

   <EditText
       android:id="@+id/password_edit_alert_dialog"
       android:enabled="false"
       android:layout_height="wrap_content"
       android:layout_width="fill_parent"
       android:layout_marginLeft="20dip"
       android:layout_marginRight="20dip"
       android:scrollHorizontally="true"
       android:autoText="false"
       android:capitalize="none"
       android:gravity="fill_horizontal"
       android:password="true"
       android:textAppearance="?android:attr/textAppearanceMedium" />

Это было полезно?

Решение

Вы правы, что вы не можете выполнить операции пользовательских интерфейсов из фоновой резьбы. Способ сделать это, чтобы использовать Handler что вы уже реализовали, чтобы всплыть диалог. Так что-то вроде:

private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        switch(msg.what){
        case GroupsActivity.DISMISS_PROGRESS_DIALOG:
            //your existing dismiss code
            break;
        case GroupsActivity.CREATE_PROGRESS_DIALOG:
            //create the dialog
            break;
        }
    }
};

Тогда ваш метод прогона будет:

public void run() {

    secInf = mGroupId.getSecurityInformation();
    if (secInf.getAdmissionLevel() == CreateGroupDialog.PRIVATE_KEY_ACCESS) {
        // do stuff
        mHandler.sendMessage(Message.obtain(mHandler,
            GroupsActivity.CREATE_PROGRESS_DIALOG));
        // do more stuff
    } else {
        mService.joinGroup(mGroupId);
        // Notifies handler to dismiss ProgresDialog and start activity
        mHandler.sendMessage(Message.obtain(mHandler,
            GroupsActivity.JOIN_SUCCESSFUL));
    }
}

Другие советы

Ты прав. Фоновые потоки не могут всплыть диалоги. Что вам нужно, это Handler На вашей ui поток для всплывающего диалога для вас.

Хотя это не хорошая идея идеи, чтобы сделать это, и этот ответ предназначен только для полноты, только видимость, показывающая диалоговое окно без пользовательской нити.

handlerThread = HandlerThread("myHandlerThread")
handlerThread?.start()
handler1 = Handler(handlerThread?.looper)

handler1?.post {
    AlertDialog
        .Builder(this)
        .setPositiveButton("ok") { dialogInterface: DialogInterface, i: Int -> dialogInterface.dismiss() }
        .create()
        .show()
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top