Popping une boîte de dialogue à partir d'un fil non-UI
-
09-10-2019 - |
Question
Je développe une application de réseau, qui est orienté groupe. La chose est que quand je suis sur le point de se joindre à un groupe, il vérifie d'abord si le groupe est sûr, et si oui, il demande utilisateur et mot de passe. Obtenir la sécurité du groupe peut prendre quelques secondes pour que je frayer un nouveau fil pour l'ensemble du processus. Je voudrais faire apparaître une boîte de dialogue dans le cas où le groupe a besoin de sécurité. Je pense qu'il peut avoir à faire avec des fils de fond, ils ne peuvent pas être en mesure de pop-up Dialogs ... Mais la chose est que je dois vérifier la sécurité du groupe dans le thread d'arrière-plan, car il faut un peu de temps.
quiconque L'espoir peut venir avec la solution ou un moyen de demander à l'utilisateur / pass que lorsque le groupe est sécurisé. Voici le fil de fond:
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));
}
Où showUserPasswordDialog fait (Mactivity est l'activité qui a donné naissance à ce fil):
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();
}
Je reçois cette exception:
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
Le fichier de mise en page XML est:
<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" />
La solution
Vous avez raison que vous ne pouvez pas effectuer des opérations UI d'un fil d'arrière-plan. La façon de le faire est d'utiliser le Handler
que vous avez déjà mis en œuvre pour faire apparaître la boîte de dialogue. Donc, quelque chose comme:
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;
}
}
};
Ensuite, votre méthode d'exécution serait:
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));
}
}
Autres conseils
Vous avez raison. fils d'arrière-plan ne peuvent pas apparaître les boîtes de dialogue. Ce que vous avez besoin est un Handler
sur votre thread d'interface utilisateur pour faire apparaître la boîte de dialogue pour vous.
Bien qu'il ne soit pas une bonne idée d'idée de le faire, et cette réponse est pour l'amour d'exhaustivité, ce qui montre la forme de dialogue fil non-UI est 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()
}