The specified child already has a parent. You must call removeView() on the child's parent first

StackOverflow https://stackoverflow.com/questions/23671530

  •  23-07-2023
  •  | 
  •  

質問

I have create a singleton helper class for creating the dialogs I need to use across my application.

The class looks like this:

public class DialogHelper {

private static final String TAG = DialogHelper.class.getSimpleName();
public static final int CHOOSE_COUNTRY_DIALOG = 1;
public static final int DISTANCE_UNIT_DIALOG = 2;
public static final int COUPON_DIALOG = 3;
public static final int VERSION_DIALOG = 4;

private static DialogHelper instance = null;
private AlertDialog.Builder builder;
private AlertDialog dialog;
private ListView dialogList;

private static Activity activity;
private Context context;

private DialogHelper(Context context) {
    CupsLog.d(TAG, "DialogHelper()");
    this.context = context;
    this.activity = (Activity) context;
    builder = new AlertDialog.Builder(context);
    dialogList = new ListView(context);
}

public static DialogHelper getInstance(Context context) {
    if (instance == null) {
        instance = new DialogHelper(context);
    }
    else
    {
        activity = (Activity)context;
    }
    return instance;
}

public AlertDialog getAlertDialog(int dialogType)
{
    switch (dialogType)
    {
        case CHOOSE_COUNTRY_DIALOG:
        {
            builder.setTitle(R.string.choose_country_title_string);
            configureDialogListView(dialogType);
            builder.setView(dialogList);
            break;
        }
        case DISTANCE_UNIT_DIALOG:
        {
            builder.setTitle(R.string.distance_units_string);
            configureDialogListView(dialogType);
            builder.setView(dialogList);
            break;
        }
        case COUPON_DIALOG:
        {
            builder.setTitle(activity.getResources().getString(R.string.coupon_dialog_title));
            final EditText input = new EditText(activity);
            builder.setView(input);
            builder.setPositiveButton(R.string.ok_string, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    Editable value = input.getText();
                    AsyncHttpClient client = new AsyncHttpClient();
                    client.setCookieStore(CookieUtil.getInstance(activity).getPersistentCookieStore());

                    CupsLog.d(TAG, "promotion url " + Consts.stringUri("/account/promotion?code=" + Uri.encode(value.toString())));
                    client.post(Consts.stringUri("/account/promotion?code=" + Uri.encode(value.toString())), new JsonHttpResponseHandler() {

                        @Override
                        public void onSuccess(int arg0, JSONObject arg1) {
                            CupsLog.d(TAG, "onSuccess(int arg0, JSONObject arg1)");
                    /*String title = null;*/
                            String msg = null;
                            try {
                                CupsLog.d(TAG, "promotion response JSON: " + arg1.toString(3));
                                msg = arg1.getString("msg");
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                            if (/*title != null && */msg != null) {
                                AlertDialog.Builder response = new AlertDialog.Builder(activity);
                                //response.setTitle(title);
                                response.setMessage(msg);
                                response.setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {

                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        AccountService.getInstance(activity).pullAccountDetailsFromServer();
                                    }
                                });
                                response.show();
                            }
                        }

                        @Override
                        public void onFailure(Throwable arg0, JSONObject arg1) {
                            CupsLog.d(TAG, "onFailure(Throwable arg0, JSONObject arg1)");
                            String msg = null;
                            try {
                                CupsLog.d(TAG, "promotion response JSON: " + arg1.toString(3));
                                msg = arg1.getString("msg");
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                            if (/*title != null && */msg != null) {
                                AlertDialog.Builder response = new AlertDialog.Builder(activity);
                                //response.setTitle(title);
                                response.setMessage(msg);
                                response.setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {}
                                });
                                response.show();
                            }
                            super.onFailure(arg0, arg1);
                        }
                    });
                }
            });
            break;
        }
    }

    builder.setNegativeButton(activity.getResources().getString(R.string.close), new android.content.DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });

    dialog = builder.create();
    if (dialogType == COUPON_DIALOG)
    {
        dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
    }
    return dialog;
}

private void configureDialogListView(int dialogType)
{
    dialogList.removeAllViewsInLayout();
    switch (dialogType)
    {
        case CHOOSE_COUNTRY_DIALOG:
        {
            dialogList.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int arg2, long arg3) {
                    String chosenUnit = ((TextView) view).getText().toString();
                    String countryString;
                    if (chosenUnit.equals(activity.getResources().getString(R.string.israel_string))) {
                        countryString = "il";
                    } else {
                        countryString = "us";
                    }
                    dialog.dismiss();
                    ((LoginActivity)activity).onCountryFound(countryString);
                }
            });
            String[] stringArray = new String[]{activity.getResources().getString(R.string.usa_string), activity.getResources().getString(R.string.israel_string)};
            ArrayAdapter<String> modeAdapter = new ArrayAdapter<String>(activity, android.R.layout.simple_list_item_1, android.R.id.text1, stringArray);
            dialogList.setAdapter(modeAdapter);
            break;
        }
        case DISTANCE_UNIT_DIALOG:
        {
            dialogList.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int arg2, long arg3) {
                    String chosenUnit = ((TextView)view).getText().toString();
                    App.getInstance().isDistanceUnitChanged = true;
                    if (chosenUnit.equals(activity.getResources().getString(R.string.metric_string))){
                        BusProvider.getInstance().post(new DialogChangeEvent(Consts.DISTANCE_UNIT, activity.getResources().getString(R.string.metric_string)));
                        FileAccessUtil.getInstance(activity.getApplicationContext()).setStringProperty(Consts.DISTANCE_UNIT, Consts.DISTANCE_UNIT_KILOMETER);
                    }
                    else {
                        BusProvider.getInstance().post(new DialogChangeEvent(Consts.DISTANCE_UNIT, activity.getResources().getString(R.string.imperial_string)));
                        FileAccessUtil.getInstance(activity.getApplicationContext()).setStringProperty(Consts.DISTANCE_UNIT, Consts.DISTANCE_UNIT_MILE);
                    }
                    dialog.dismiss();
                }
            });
            String[] stringArray = new String[] { activity.getResources().getString(R.string.metric_string), activity.getResources().getString(R.string.imperial_string)};
            ArrayAdapter<String> modeAdapter = new ArrayAdapter<String>(activity, android.R.layout.simple_list_item_1, android.R.id.text1, stringArray);
            dialogList.setAdapter(modeAdapter);
            break;
        }
    }
}
}

Now, to show the needed dialog I use this line of code:

DialogHelper.getInstance(this).getAlertDialog(DialogHelper.DISTANCE_UNIT_DIALOG).show();

And it all works great, for the first time. For the second time I get the exception specified in the title. Now, from previous questions I searched here I understand that I probably showing the dialog for the first time, and for the second time it probably attached to the parent activity.

The question is: How can I handle this situation from inside the helper class without tight coupling it to a specific activity?

役に立ちましたか?

解決 2

From my understanding the problem in my case was the fact that I tried to attach the same ListView to the same Dialog builder so creating a new instance of both of them removed this error. So what I did was at the beginning of the getAlertDialog method I added this:

 public AlertDialog getAlertDialog(final int dialogType)
 {
    builder = new AlertDialog.Builder(activity);
    dialogList = new ListView(activity);
    ...

他のヒント

    Because problem is in instance create
    in your Code

    static DialogHelper storedInstance;
    public static DialogHelper getInstance(Context context) {
       if (instance == null) {
            instance = new DialogHelper(context);
        }
        else
        {

            activity = (Activity)this.context;
        }

        return instance;
    }

    First time you pass Contect and Create dialog successfully with Context but second time you pass second reference context and instance already created so it returns previous context instance.that is problem...
    so 2 way to solve problem
    first Close agove dialog and every time create new Dialog instance
    or
    second is return privois dialog reference like this

    public static DialogHelper getInstance(Context context) {
         if (instance == null) {
            instance = new DialogHelper(context);
            storedInstance=instance ;
        }
        else
        {
           instance=storedInstance;
        }
  return instance;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top