1

I'm popping up an AlertDialog when a ListView item is clicked and the string of the message is very large (nearly 20,000 characters). What winds up happening is that I click the list item and it sits for about 3-4 seconds before displaying the AlertDialog. This is problematic for many reasons, primarily that the user could click the button repeatedly and crash the app.

My first thought was to try to mimic how the Google Play app handles their open source license display (Play -> Nav Drawer -> Settings -> Open Source License info), where they pop open the AlertDialog and then it looks as though the view/text is loaded after the dialog is shown. I imagined it looking something like this:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
       builder.setTitle(title);
       builder.setMessage(veryLongStringMessage);
       builder.setCancelable(true);
       builder.setNeutralButton(android.R.string.ok, listener);

       final AlertDialog alertDialog = builder.create();
       alertDialog.show();

Pretty basic stuff up until this point. Then I've tried to remove the message set in builder for something like:

builder.setMessage("")
// create/show dialog as above
alertDialog.setMessage(veryLongStringMessage);

But that seems to just load the whole dialog before showing it. So I thought maybe post a runnable to go at the end of the activity calls, and that wasn't working. I tried doing this in an Async task and could not get it working that way either. I've tried this as a DialogFragment where I call

activity.getSupportFragmentManager().executePendingTransactions();

Then go on to try to set the message after I know the DialogFragment has been shown and I either wind up with an empty dialog (the new message won't show up) or it loads it all at once and I'm sitting with that 3-4 second delay.

Anyone have any good method of implementing and AlertDialog with a very large message?

Wes Winn
  • 551
  • 5
  • 15

2 Answers2

3

This case is when I show the legal notices of Google Play Services:

The problem seems to be the Dialog.show(), it takes those seconds in order to generate the layout. So what I have done in my case, probably not the best one but it works. I create a temporal dialog.

private void showGPSLicense() {
        AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MyActivity.this);
        LicenseDialog.setTitle(getString(R.string.google_maps_legalnotices));
        LicenseDialog.setMessage(getString(R.string.google_maps_loading));
        final Dialog loadingDialog = LicenseDialog.create();  
        loadingDialog.show();       

       //This dialog does not take much time. Meanwhile I get via AsyncTask the heavy message, replacing/dismissing the previous dialog.

        (new AsyncTask<Void, Void,AlertDialog.Builder>() {
            @Override
            protected AlertDialog.Builder doInBackground(Void... arg0) {
                String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(getApplicationContext());
                AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MyActivity.this);
                LicenseDialog.setTitle(getString(R.string.google_maps_legalnotices));
                LicenseDialog.setMessage(LicenseInfo);
                return LicenseDialog;
            }

            protected void onPostExecute(AlertDialog.Builder result) {
                Dialog dialog = result.create();
                dialog.setOnShowListener(new OnShowListener() {

                    public void onShow(DialogInterface dialog) {
                        loadingDialog.dismiss();
                    }
                 });
                dialog.show();
             }
        }).execute();   
}

Tested on Nexus 5 (4.4.2)

If you are worried about many clicks you can also prevent many clicks by implementing the OnClickListener:

public abstract class PreventManyClicksListener implements OnClickListener {
    private boolean clickable = true;

    public abstract void preventManyClicks(View view);

    public final void onClick(View view) {
        if (clickable) {
            clickable = false;
            preventManyClicks(view);
        }
    }

    public void setClickable() {
        clickable = true;
    }
}
//...

private PreventManyClicksListener preventDialog = new PreventManyClicksListener() {         
@Override
public void preventManyClicks(View view) {
    showGPSLicense();
    setClickable();
}
};
//.. 
myView.setOnClickListener(preventDialog);
AlexBcn
  • 2,450
  • 2
  • 17
  • 28
0

I think you need to use a custom view in order to be able to do this, because you can't update an AlertDialog message after it's been created. Create a custom view with a TextView with an id of textView1 and ProgressBar with id of progressBar1 then create the following class.

public class MyDialogFragment extends DialogFragment {
    private TextView mTextView;
    private ProgressBar mProgressBar;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.my_dialog, container, false);
        mTextView = view.findViewById(R.id.textView1);
        mTextView.setVisibility(View.GONE);
        mProgressBar = view.findViewById(R.id.progressBar1);
        mProgressBar.setVisibility(View.VISIBILE);

        return view;    
    }

    @Override
    public View onStart() {
        super.onStart();

        mTextView.setText(getArguments().getString("text");
        mProgressBar.setVisibility(View.GONE);
        mTextView.setVisibility(View.VISIBILE);
    }
}

You also need to pass it the text string in its arguments.

DialogFragment dialog = new MyDialogFragment();
Bundle args = new Bundle();
args.putString("text", text);
dialog.setArguments(args);
dialog.show(getFragmentManager(), "my_dialog")
ashishduh
  • 6,629
  • 3
  • 30
  • 35
  • Unfortunately with a custom view placed in a DialogFragment as described, the same behavior seems to occur. I click the ListItem, see no ProgressBar and it hangs until the DialogFragment is finally shown. I did confirm the ProgressBar was being called and dismissed, but it seems that making the text visible is actually what's slowing things down, and it's getting lumped in with showing the dialog. Thanks for the tip though! – Wes Winn May 29 '14 at 15:07
  • You say you've already tried background thread like [this answer](http://stackoverflow.com/a/8581699/1199931)? If that's the case, then the only other option I can think of is to page the long text, by using a ListView (which will dynamically load only the text that is on screen as you know). You can split the long string into equal parts for the ListView using something like [this](http://stackoverflow.com/a/3761521/1199931). – ashishduh May 29 '14 at 15:43