2010-12-13 7 views
4

Ich entwickle eine Netzwerk-App, die gruppenorientiert ist. Die Sache ist, dass, wenn ich mich einer Gruppe anschließe, zuerst überprüft wird, ob die Gruppe sicher ist, und wenn ja, fragt sie nach Benutzer und Passwort. Die Gruppensicherheit kann einige Sekunden dauern, sodass ich einen neuen Thread für den gesamten Prozess erstellen kann. Ich würde gerne einen Dialog öffnen, falls die Gruppe Sicherheit braucht. Ich denke, dass es vielleicht mit Hintergrundthreads zu tun hat, sie können Dialoge vielleicht nicht öffnen ... Aber die Sache ist, dass ich die Gruppensicherheit im Hintergrundthread überprüfen muss, weil es ein bisschen Zeit braucht.Dialog aus einem Nicht-UI-Thread herauskommen

Hoffe, dass jeder mit der Lösung oder einem Weg kommen kann, Benutzer/Pass nur zu fragen, wenn die Gruppe sicher ist. Hier ist der Hintergrund-Thread:

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

Wo showUserPasswordDialog tut (mActivity ist die Aktivität, die diesen Thread erzeugt):

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

} 

Ich erhalte diese Ausnahme:

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 

Die XML-Layout Datei ist:

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

Antwort

6

Sie haben Recht, dass Sie keine UI-Vorgänge von einem Hintergrundthread ausführen können. Der Weg dazu besteht darin, die Handler zu verwenden, die Sie bereits implementiert haben, um den Dialog zu öffnen. So etwas wie:

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

dann Ihre run-Methode wäre:

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

Sie sind richtig. Hintergrundthreads können keine Dialoge öffnen. Was Sie brauchen, ist ein Handler in Ihrem UI-Thread, um den Dialog für Sie zu öffnen.

Verwandte Themen