Intent intent = new Intent(this, SlideshowActivity.class); intent.putExtra("videoUri", videoUri); intent.putExtra("imageFileNames", images); intent.putExtra("selectedSong", song); startActivity(intent);And here is code from SlideshowActivity to retrieve this data:
Intent intent = getIntent(); ArrayList<String> images = intent.getStringArrayListExtra("imageFileNames"); Song song = intent.getParcelableExtra("selectedSong"); // custom Parcelable class Uri videoUri = intent.getParcelableExtra("videoUri");There is an obviously ugly issue here. Both Activities need to know the keys (imageFileNames, selectedSong, videoUri) to use to put/get from the Intent's extras. This is such a common thing in Android, even in the framework, that there is a simple pattern for dealing with it. Just use public constants declared in the class that will use the Intent extras:
public class SlideshowActivity extends Activity{ public static final String EXTRA_IMAGE_FILE_NAMES = "imageFilesNames"; public static final String EXTRA_SELECTED_SONG = "selectedSong"; public static final String EXTRA_VIDEO_URI = "videoUri"; ... Intent intent = getIntent(); ArrayList<String> images = intent.getStringArrayListExtra(EXTRA_IMAGE_FILE_NAMES); // etc.And then of course in the calling class you would now have:
intent.putExtra(SlideshowActivity.EXTRA_IMAGE_FILES_NAMES, images): // etc.Problem solved, right? Well not exactly. You still don't know what the types of the extras should, and you do not know if a particular extra is required or optional. Documenting your code can help with this:
public class SlideshowActivity extends Activity{ /** * An ArrayList of Strings. Required. */ public static final String EXTRA_IMAGE_FILE_NAMES = "imageFileNames"; ... }So we put the type information and wether the field is required or not as a comment. Wait, doesn't this feel more like Ruby or Python instead of Java? Isn't there some way to use the language syntax and compiler to state this information in a better way instead of relying on code comments? That's where the Static Starter Pattern kicks in:
public class SlideshowActivity extends Activity{ public static void start(ArrayList<String> images, Song song, Uri videoUri, Context ctx){ Intent intent = new Intent(ctx, SlideshowActivity.class); intent.putExtra(EXTRA_IMAGE_FILE_NAMES, images); intent.putExtra(EXTRA_SELECTED_SONG, song); intent.putExtra(EXTRA_VIDEO_URI, videoUri); ctx.startActivity(intent); } ... }From this method signature, I know the types of all of the extras and I know that they are all required. If I wanted to make one of them optional, then I could simply overload the start method with only two of the parameters, removing the optional parameter. Of course, somebody could bypass this and still use an Intent.
Now this is not the best pattern for every Activity. The most obvious example is if you want your Activity to be started by other applications. Another application won't be able to invoke a static method. You will have to use the action/Intent-filter path for this. Of course this is pretty rare, how many of your Activities are meant to be started by other apps? Even if this is the case, you can still use the pattern for use within your app.
This pattern is also not limited to Activities. You can do it with Services as well, especially IntentServices:
public class AwesomeService extends IntentService{ public static void start(String someString, int someInt, Context ctx){ Intent intent = new Intent(ctx, AwesomeService.class); intent.putExtra(EXTRA_SOME_STRING, someString); intent.putExtra(EXTRA_SOME_INT, someInt); ctx.startService(intent); } }If your IntentService handles multiple actions, this can be built into the pattern:
public class AwesomeService extends IntentService{ public static startUploadFile(String someFileName, Context ctx){ Intent intent = new Intent(ctx, AwesomeService.class); intent.setAction(ACTION_UPLOAD_FILE); // ACTION_UPLOAD_FILE is a constant intent.putExtra(EXTRA_SOME_FILE_NAME, someFileName); ctx.startService(intent); } }You get the idea. You could extend this to BroadcastReceivers as well. I discussed this pattern a bit with my Android in Practice co-author, Charlie Collins. He liked it too, and pointed out that others have used it as well. Personally, I'm not a fan of static methods or of passing around the Context like that, but the positives seem to outweigh the negatives. What do you think? Useful? Over-engineered?
7 comments:
Smart idea!
This is exactly the kind of practice promoted by Effective Java, using the compiler to avoid mistakes, and I think it works well.
I like pass Intent created like 'new Intent(this, SomeActivity.class)' and pass to static method that will just add extras. With this modified intent you can call startActivity or whatever you want.
i just discovered that google does this in their own contacts app. take a look at the buildIntent method here (https://github.com/android/platform_packages_apps_contacts/blob/master/src/com/android/contacts/activities/PhotoSelectionActivity.java) for example.
For an even more automated way to do this, have a look at Android Annotations, and its IntentBuilder: https://github.com/excilys/androidannotations/wiki/HowItWorks#StartingAnAnnotatedActivity
Starter pattern does not run until I set flag to intent as follows
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
otherwise it gives exception as follows
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Why?
We are a third party technical support service. Avast Customer Support is here to help you out with the whole procedure to Download Avast Antivirus online, We not only fix your Avast Support related issues but will guide with how to get started with your new Avast product once it gets installed successfully.We at Avast Tech Support provides service to protect your PC from potential online threats and external attacks like viruses, Trojans, malwares, spywares and phishing scams. And Avast Refund. Call on our Avast Phone Number.
Gmail Customer service is a third party technical support service for Gmail users when they face any technical issue or error in their Gmail account. Our Gmail Customer Support team solves issues like forgot Gmail account password, Gmail configuration or Sync issues, recover deleted emails and many more.
How you install or reinstall Office 365 or Office 2016 depends on whether your Office product is part of an Office for home or Office for business plan. If you're not sure what you have, see what office com setup products are included in each plan and then follow the steps for your product. The steps below also apply if you're installing a single, stand-alone Office application such as Access 2016 or Visio 2016. Need Help with office setup Enter Product Key?
Norton Tech Support is a third party service provider and not in any way associated with Norton or any of its partner companies. At Norton Support we offer support for Norton products and sell subscription based additional warranty on computer and other peripheral devices.
Post a Comment