From the course: Android Development Tips

Create a reusable dialog class - Android Tutorial

From the course: Android Development Tips

Create a reusable dialog class

- [Narrator] In Android apps, dialogs are used to communicate with the user and also sometimes to collect small amounts of information, but creating dialog classes and layouts takes some time. If you want to use them at all, it's a good idea to create reusable classes, that can be used multiple times in your apps. In this tip I'm going to share some code that I created for one of my apps that's saved me a lot of time. I had to collect little bits of text from the user in different contexts. The prompt might change, the value might change, but I wanted the dialog to always look the same, so I created a reusable Java class. I'll start by creating a layout file that defines my dialog's user interface. I'll go to my layout folder, under resources, and I'll create a new layout resource file. I'll name it dialog_edit_text. I won't worry about the Root element, because I'm going to go get the code from a gist on GitHub. Notice as I add files, I'm adding them to my GitHub repository. Now I'll go to a browser, and I'll navigate to "git.io/v9i07," and that takes me to this gist that's labeled "dialog_edit_text.xml." I'll select and copy all this code, and I'll go back to Android Studio. Then I'll paste it into place. Here's what my dialog will look like. There's a text view at the top that has the text "Prompt Text," and then there's an edit text component. Then there's a CANCEL and an OK button. This is all being laid out using a relative layout. If you prefer, you could use a constraint layout. Notice that each of these view objects has a unique ID, and I have an ignore attribute here for hard coded text, because I only have this text in here for development and testing. I'll be updating that text dynamically each time I use the dialog. Here are my buttons down here, and they don't have any onclick attributes or any other ways of reacting when the user clicks them. Next, I'll create my Java class. I'm going to put this in a new package that I'll name "Dialogs," and I'll name my new Java class "EditTextDialog." Once again I'll add this to Git, and I'm going to get rid of everything except for the package declaration. Then, once again, I'll go back to my browser, and this time I'll go get a gist that's at "git.io/v9i0w." This is named EditTextDialog.java. I'll select everything after the package declaration. You can see there's quite a bit of code involved here. I'll paste that into place. Now let's take a look at what this code is doing. First of all, this class extends DialogFragment. It has two fields named "PROMPT_KEY" and "VALUE_KEY. And there's a newInstance method that lets me pass in those two values. Those values are saved to a bundle, and then they're passed to a fragment using the setArguments method. The fragment is an instance of this class. This is a factory method that lets me customize this version of the dialog. Next, there's the implementation of the onAttach method. This is a fragment, and so each time it's loaded by its host activity, this method will be called. A context will be passed in. The context must implement an interface named "EditTextDialogListener," which is declared down at the bottom of this class. I'll get back to that in a moment. If the caller of this dialog does implement that interface, then I save the reference to that caller in the "mListener" field. If not, then I throw an exception. That means that this class hasn't been used correctly. Next is the onCreateView method. This is called automatically as the fragment manager sets up the fragment. This is where I'm laying out the dialog, displaying all the values that were passed in, and setting up the event handlers. If you prefer, you could change some of this code to use Butter Knife, and it would make the code more readable and maintainable. Now to the interface. This interface declares a single abstract method called onEditTextDialogOK, and it's only going to be called if the user clicks the YES or OK button on the dialog. In order to use this dialog class, the caller must implement that interface. I'll go back to my main activity, and I'll add an implements clause, and I'll pass in "EditTextDialogListener." That generates an error condition, so I'll use an intention action and choose "Implement Methods," and I'll choose that one method. Now this is a listener for that dialog. Now I'm ready to actually call the dialog. I'll do this work in my runCode method up here. I'll create an instance of the dialog. I'll set the type as "EditTextDialog." I'll just call it "Dialog," and I'll call the classes "newInstance" method. I'll pass in a string of "Enter your name." That will be the prompt, and then an empty string as the current value. Next, to display the message, I'll call "dialog.show," and I need to pass in an instance of the fragment manager. Now there's a couple of ways of doing this. You need to know whether you're using the native version of this class or the support version. I'll go back to "EditTextDialog," and scroll up to the top. Then I'll hold down Control or Command and float the cursor over it. I see that my dialog fragment is a member of the support library. It's not a member of the Core SDK. I'm going to pass in the results of a call to a method called "getSupportFragmentManager." If I were using the native version of the fragment, I would just call "getFragmentManager." Then I need to pass in a string that's called a tag. When you're working with fragments, tags can be used to get references to existing fragments. This tag can be anything. I'll just call it "dialog_tag," and these are usually set up as constants. I'll select Refactor, Extract, Constant, and I'll accept the default name, "DIALOG_TAG." That's now declared as a constant up at the top of my code. Finally, I'll add some code into my implementation of onEditTextDialogOK. I'll call my log method. I'll say, "'You entered a value of ' + newValue." Now all the pieces of the puzzle are put together. When the user clicks the button in the activity, that creates and shows the dialog. The user will then fill in the value in the dialog, touch the OK button, and that will call the listener method in the activity again and close the dialog. Now click the Run Code button, and there's my dialog. I'll enter my name and click OK, and I get "You entered a value of David." Now if I click the Run Code button again, I see the dialog again, but it doesn't remember the value I originally entered. Here's how you can do that. I'll cancel out of the dialog and come back to Android Studio. Up at the top of my class, I'll declare a string field, and I'll initialize it as an empty string. Then down here where I'm calling the dialog, instead of passing in a literal empty string, I'll pass in that field. Finally, I'll go down to my listener method, and I'll save the value that the user entered with "name_= newValue." Now each time the user calls the dialog and enters a value, I'm saving it persistently to the activities field. Right now, the lifetime of that value will only be for the current activity session. If the user rotates the device or otherwise changes the configuration, that value could be lost, but there are lots of ways of dealing with that. I'll run the application again and run the code again. I'll type my name and click OK. Then I'll run the code again, and this time the value is remembered. Now I can use this dialog wherever I want to in my application. I can change the prompt, and I can change the value that's being passed in depending on the context of how the dialog is being used. I now have some reasonable code that can be used multiple times throughout my Android app.

Contents