Pregunta

Estoy desarrollando una aplicación de red, que está orientada grupo. Lo que pasa es que cuando estoy a punto de unirse a un grupo, se comprueba en primer lugar si el grupo es seguro, y si es así, pide usuario y contraseña. Obtener la seguridad del grupo puede tomar un par de segundos, así que generar un nuevo subproceso para todo el proceso. Me gustaría para que aparezca un cuadro de diálogo en caso de que el grupo requiere seguridad. Estoy pensando que puede tener que ver con hilos de fondo, es posible que no pueda aparecer cuadros de diálogo ... Pero la cosa es que necesito para comprobar la seguridad del grupo en el subproceso en segundo plano, ya que toma un poco de tiempo.

La esperanza alguien puede llegar a la solución o cualquier forma de pedir de usuario / contraseña sólo cuando el grupo es seguro. Aquí está el hilo de fondo:

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

Donde showUserPasswordDialog hace (mActivity es la actividad que dio lugar a este hilo):

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

 }

Me estoy poniendo esta excepción:

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

El archivo de diseño XML es:

   <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" />

¿Fue útil?

Solución

Tiene razón en que no se pueden realizar operaciones de interfaz de usuario desde un subproceso en segundo plano. La manera de hacerlo es utilizar el Handler que ya se han implementado para el cuadro de diálogo emergente. Así que algo como:

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

A continuación, el método run sería:

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

Otros consejos

You are correct. Background threads cannot pop up dialogs. What you need is a Handler on your UI thread to pop up the dialog for you.

Although it is not a good idea idea to do it, and this answer is for completeness sake only, showing dialog form non-UI thread is possible.

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

handler1?.post {
    AlertDialog
        .Builder(this)
        .setPositiveButton("ok") { dialogInterface: DialogInterface, i: Int -> dialogInterface.dismiss() }
        .create()
        .show()
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top