質問

I want to show custom dialog using DialogFragment. However I fail to initialise layout Views before I need to modify them.

This is my DialogFragment class.

public class RemoteProgressDialog extends DialogFragment {

private TextView lockProgress;
private TextView foldProgress;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Dialog_NoActionBar);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.remote_progress_dialog, null);
    lockProgress = (TextView) view.findViewById(R.id.lock_progress);
    return view;
}

public void lockFinished() {
    lockProgress.setCompoundDrawables(
                                    null,
                                    getResources().getDrawable(R.drawable.icn_mycar_sunroof_open),
                                    null, null);
    // TODO: remove
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    showLockProgress(false);
    dismissDialogIfNeeded();
}

public void showLockProgress(boolean show) {
    lockProgress.setVisibility(show ? View.VISIBLE : View.GONE);
}

private void dismissDialogIfNeeded() {
    if (lockProgress.getVisibility() == View.GONE) {
        // TODO: add conditions
        dismiss();
    }
}

I show the dialog in a Fragment like this:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    progressDialog = new RemoteProgressDialog();
}

@Override
public boolean onLongClick(View v) {
    progressDialog.show(getFragmentManager(), REMOTE_PROGRESS_DIALOG);
    progressDialog.showLockProgress(true);
    return true;
}

At first I tried to build the Dialog using AlertDialog.Builder but I was getting NullPointerException because onCreateDialog() method was not performed before showLockProgress() so lockProgress was null. Well, I didn't need AlertDialog anyway so I end up using this approach hoping it would help to solve the problem.

Unfortunately it didn't help. lockProgress is still null when the method showLockProgress() is called. I put a breakpoint in onCreate() and onCreateView() methods of the DialogFragment as well as in onAttach() of hosting Fragment. The one in onAttach() gets triggered so the instance of DialogFragment should be created but neither onCreate() nor onCreateView() seem to be called. When I long-press the button, showLockProgress() is called but lockProgress is still null.

Why aren't my views initialised when the instance of dialog is created or immediately after I call DialogFragment.show() method?

役に立ちましたか?

解決

So the problem I guess is that your public method is called before onCreate and etc. because after calling show to your DialogFragment it takes time to initialise the dialog, it's view and all variables. So the way you can handle this the right way in my opinion is just create a boolean variable which you set before showing your DialogFragment. Something like this :

public class RemoteProgressDialog extends DialogFragment {

    private boolean mShowText = false; // default value

    private TextView lockProgress;

    public void setShowText(boolean showText){
        this.mShowText = showText;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.remote_progress_dialog, null);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState){
        // initialise your views here
        lockProgress = (TextView) view.findViewById(R.id.lock_progress);
        showLockProgress(mShowText);
    }

    public void showLockProgress(boolean show) {
        lockProgress.setVisibility(show ? View.VISIBLE : View.GONE);
    }

}

and you can do something like this before showing your Dialog :

progressDialog.show(getFragmentManager(), REMOTE_PROGRESS_DIALOG);
progressDialog.setShowText(true);

So this way you won't get NullPointerException and you can be sure that depending on the boolean which you set, your TextView in RemoteProgressDialog will be hidden or visible when it is initialised.

Hope this helps!

他のヒント

Problem:

I think the problem is that you try to showLockProgress before the dialogFragment is created and displayed which leads to an attempt to access lockProgress before it's assigned.

@Override
public boolean onLongClick(View v) {
    progressDialog.show(getFragmentManager(), REMOTE_PROGRESS_DIALOG);
    progressDialog.showLockProgress(true);
    return true;
}

Here is what happens when you execute that code:

  • The DialogFragment's show method "is a convenience for explicitly creating a transaction, adding the fragment to it with the given tag, and committing it" - it creates a transaction to add a fragment and commit it.
  • But the FragmentTransaction's commit method actually schedules the commit of the transaction at some point in the future, when the main thread is ready.
  • The onLongClick method is executed on the main thread so the actuall commit of the transaction (along with the fragment creation) is scheduled to happen at some point after this method finishes. But inside it you try to access the stil-not-initialized member lockProgress (inside showLockProgress).

Solution:

Use the Android-Developer's idea and implement a boolean member that can be used to show (or not) the progress after the view was created (in onViewCreated for example). This way you only tell the DialogFragment from outside that it should display the progress (or not) but let it deal internally with the "when" and "how".

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top