How do I make my activity use testing data? - android

I have an application which displays data (posts) from a web API.
A background service syncs this data at some unknown time and saves it.
When visiting my main activity it loads this data and displays it in a RecyclerView
The loading is handled via a singleton class
I currently test the main activity as follows
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
#Test
public void testDataLoad() {
int postsTotal = DataSingleton.getInstance().getPostsCount();
ViewInteraction empty = onView(withId(R.id.empty_view));
ViewInteraction recycler = onView(withId(R.id.recycler_view));
if (postsTotal == 0) {
empty.check(matches(isDisplayed()));
recycler.check(matches(not(isDisplayed())));
} else {
empty.check(matches(not(isDisplayed())));
recycler.check(matches(isDisplayed()));
recycler.check(new RecyclerViewItemCountAssertion(greaterThan(postsTotal)));
}
}
I know that this can't be the right way to write tests. I want to be able to test both with an empty data set and a non-empty set so that the if-else is two separate tests. The only way I think I can achieve it is to mock the data.
Is there another way?
Can I use Mockito to make the MainActivity use mock data without modifying the production code? Is my only choice to make it inject either real or mocked data providers in place of my singleton?
Is it better to just uninstall and reinstall my app each time so there is no data to start with and then continue with real data testing?

Android Activity are heavyweight and hard to test. Because we don't have control over the constructor, it is hard to swap in test doubles.
The first thing to do is to make sure you are depending on an abstraction of the data-source rather than a concretion. So if you are using a singleton with a getPostsCount() method then extract an interface:
interface DataSourceAbstraction {
int getPostsCount();
}
Make a wrapper class that implements your interface:
class ConcreteDataSource implements DataSourceAbstraction {
#Override
int getPostsCount() {
return DataSingleton.getInstance().getPostsCount();
}
}
And make the Activity depend on that rather than the concrete DataSingleton
DataSourceAbstraction dataSourceAbstraction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super(savedInstanceState);
injectMembers();
}
#VisibleForTesting
void injectMembers() {
dataSourceAbstraction = new ConcreteDataSource();
}
You can now swap in a test double by subclassing and overriding injectMembers that has relaxed visibility. It's a bad idea do this in enterprise development, but there are less options in Android Activities where you don't control the constructor of the class.
You can now write:
DataSourceAbstraction dataSource;
//system under test
MainActivity mainActivity
#Before
public void setUp() {
mockDataSource = Mockito.mock(DataSourceAbstraction.class);
mainActivity = new MainActivity() {
#Override
void injectMembers() {
dataSourceAbstraction = mockDataSource;
}
};
}

Related

How do I mock a class with expresso in android?

Hello I am struggling with a task that seems very simple. I need to write an expresso unit test but I need the activity to use a mocked class instead of the one it uses during the normal run.
the, the closest solution I saw was here:
Nullifying or overriding API calls made in an Activity under an Espresso test
But this requires getters and setters at the application level and only deals with constants.
Here is a simple example of want to do:
Activity:
public class MainActivity2 extends AppCompatActivity {
// how do I mock this without using any branches
// just have expresso replace with MainActivity2CustomClass with a mock?
private MainActivity2CustomClass mainActivity2CustomClass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mainActivity2CustomClass = new MainActivity2CustomClass();
mainActivity2CustomClass.foo();
}
}
the class I want to mock
// Need expresso to replace this class with a mock
public class MainActivity2CustomClass {
void foo() {
}
}
To clarify I need to do this with a large application with several classes. So using branches is NOT the solution I seek. For instance this will not work for my application
// I DO ***NOT** WANT THIS solution since it will explode in many branches in my application
Intent intent = new Intent(targetContext, PatientActivity.class);
intent.putExtra("istestrunning", 2);
// etc...
// Not acceptable solution for my problem, creates too many branches and messy code
if (getIntent().getIntExtra("istestrunning", 0) == 2) {
mainActivity2CustomClass = new MainActivity2CustomClass();
mainActivity2CustomClass.foo();
} else {
mainActivity2CustomClass2 = new MyMock();
mainActivity2CustomClass2.foo();
}
I want to know if it possible to have expresso simply replace that class at testing time. Can it be done?
Any help or leads is appreciated.
thank you.

How to unit test interaction between FragmentDialog and Activity which implements interface

I have MainActivity that shows FragmentDialog (EditIntervalFragment) in order to capture user's input. Activity implements EditIntervalListener interface. In onAtach method fragment casts activity to EditIntervalListener.
I want to test that my EditIntervalFragment properly calls EditIntervalListener methods with correct parameters.
My initial intent was to use Roblectric and Mockito. The following code almost works.
#Test
public void shouldCallInterfaceAfterModify() {
MainActivity hostActivity = Robolectric.setupActivity(MainActivity.class);
EditIntervalFragment editIntervalFragment = EditIntervalFragment.getInstance(0, TEST_NAME, TEST_DURATION);
editIntervalFragment.show(hostActivity.getSupportFragmentManager(), "test");
AlertDialog dialog = (AlertDialog) editIntervalFragment.getDialog();
assertNotNull(dialog);
EditIntervalFragment.EditIntervalListener activity = Mockito.spy(hostActivity);
dialog.findViewById(android.R.id.button1).performClick();
verify(activity).onIntervalChanged(0,TEST_NAME,TEST_DURATION);
}
The problem with this code that it uses real MainActivity. It means that all MainActivity's logic will be executed. I want to avoid this. How can I do this?
Update
I found a way to not call real MainActivity. I created another activity, just for test.
public class ActivityTest extends FragmentActivity implements EditIntervalFragment.EditIntervalListener {
//empty methods here
}
My test now looks like this
#Test
public void shouldCallInterfaceAfterModify() {
ActivityTest hostActivity = Robolectric.setupActivity(ActivityTest.class);
ActivityTest spy = Mockito.spy(hostActivity);
EditIntervalFragment editIntervalFragment = EditIntervalFragment.getInstance(0, TEST_NAME, TEST_DURATION);
editIntervalFragment.show(spy.getSupportFragmentManager(), "test");
AlertDialog dialog = (AlertDialog) editIntervalFragment.getDialog();
assertNotNull(dialog);
dialog.findViewById(android.R.id.button1).performClick();
verify(spy).onIntervalChanged(0, TEST_NAME, TEST_DURATION);
}
But after test execution I receive error saying than only spy.getSupportFragmentManager() was called. I'm 100% sure that onIntervalChanged should be called.
Looking for help. How can I implement such kind of test?
That is always challange to make work spies when you don't control lifecycle.
What we are usually doing we extracting all not related functionality to utility classes and mock them in tests. It also helps with design of the application (Single class responsibility rule).
Of course it depends if you do something with this data. If it is just data class than I would have Factory for creating this data classes and again mock it in tests. All this requires proper DI (look to Dagger).
And there is nothing wrong with your approach but it doesn't force you to think about your app as small parts that interact with each other. But at the same time it brings more complexity which pays off later
I ended up with this solution. Create an Activity that implements interface an keep track of all interaction.
public class ActivityTest extends FragmentActivity implements EditIntervalFragment.EditIntervalListener {
public int mIntervalChangedCalls = 0;
public int mPosition;
public String mName;
public long mDurationMillSec;
#Override
public void onIntervalChanged(int position, String name, long durationMillSec) {
mIntervalChangedCalls++;
mPosition = position;
mName = name;
mDurationMillSec = durationMillSec;
}
}
My test looks like this
#Test
public void shouldCallOnIntervalChanged() {
ActivityTest hostActivity = Robolectric.setupActivity(ActivityTest.class);
EditIntervalFragment editIntervalFragment = EditIntervalFragment.getInstance(0, TEST_NAME, TEST_DURATION);
editIntervalFragment.show(hostActivity.getSupportFragmentManager(), "test");
AlertDialog dialog = (AlertDialog) editIntervalFragment.getDialog();
assertNotNull(dialog);
dialog.findViewById(android.R.id.button1).performClick();
assertThat(hostActivity.mIntervalChangedCalls).isEqualTo(1);
assertThat(hostActivity.mPosition).isEqualTo(0);
assertThat(hostActivity.mName).isEqualTo(TEST_NAME);
assertThat(hostActivity.mDurationMillSec).isEqualTo(TEST_DURATION);
}
I'm not completely happy with this creation of a separate class just for test purposes. I suppose the same can be achieved with Mockito or Robolectric, but I do not know how.
So I'm still open for any ideas or suggestions. I'll accept my own answer, if no one gives better solution in a week.

How to get the activity reference before its oncreate gets called during testing

How to get the reference of Activity before its onCreate will be called. while its under test. I use ActivityTestRule as JUnit Rule. The reason for this requirement is i want to inject Mocks into activity from tests.
public class MyActivity extends Activity{
MyComponent myComponent;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(myComponent==null){
myComponent ... //initialise dagger component
}
myComponent.inject(this);
...
}
public void setComponent(MyComponent comp){
this.myComponent = comp;
}
}
public class MyTest{
#Rule
public ActivityTestRule<MyActivity> intentsTestRule = new ActivityTestRule<>(MyActivity.class);
MyComponent myFakeComponent;
#Before
public void setUp() {
MyActivity activity = intentsTestRule.getActivity();
activity.setComponent(myFakeComponent);
}
#Test
public void testMethod1(){...}
}
As per documentation, what you're doing here is wrong.
#Rule
public ActivityTestRule<MyActivity> intentsTestRule = new ActivityTestRule<>(MyActivity.class);
MyComponent myFakeComponent;
#Before
public void setUp() {
MyActivity activity = intentsTestRule.getActivity();
activity.setComponent(myFakeComponent);
}
Because,
This rule provides functional testing of a single activity.
The activity under test will be launched before each test annotated with
Test and before methods annotated with #Before.
It will be terminated after the test is completed and methods
annotated with After are finished. During the duration of the test
you will be able to manipulate your Activity directly.
However!
protected void beforeActivityLaunched ()
Override this method to execute any code that should run
before your Activity is created and launched.
This method is called before each test method,
including any method annotated with #Before.
Therefore, if you move the initialization of the MainActivityComponent outside the Activity to a place that is mockable, then you'll be able to tinker it together before the main activity is created.
EDIT:
Another possible solution is to lazily initiate the Activity as per link.
#Rule
public ActivityTestRule<NoteDetailActivity> mNoteDetailActivityTestRule =
new ActivityTestRule<>(NoteDetailActivity.class, true /* Initial touch mode */,
false /* Lazily launch activity */);
#Before
public void intentWithStubbedNoteId() {
// Add a note stub to the fake service api layer.
FakeNotesServiceApiImpl.addNotes(NOTE);
// Lazily start the Activity from the ActivityTestRule this time to inject the start Intent
Intent startIntent = new Intent();
startIntent.putExtra(NoteDetailActivity.EXTRA_NOTE_ID, NOTE.getId());
mNoteDetailActivityTestRule.launchActivity(startIntent);
registerIdlingResource();
}
Here is my sample code for that:
public class TestClass {
#Rule
public ActivityTestRule<T> activityRule = new ActivityTestRule<T>(type) {
#Override
protected void beforeActivityLaunched() {
//TODO inject mocks, setup stubs etc..
}
};
}
#Before
public void before() {
activityRule.getActivity();
}
#Test
public void myTest() {
//...
}
}
Is this code complete? I can't see you creating the dagger graph.
Anyway, what I do in my code, is to have a Static class called Injector that creates the graph for me, and also can inject elements into objects. So, in my Application Class I call it to create the graph, and all other activities just use the existent graph.
Then, in a test, you could create a fake test application class that initialize the graph in a different way, or simply recreate the graph calling the Injector methods, before the activity is created. I'm not familiar with ActivityTestRule, so I can't help much with the life cycle of this test.
But just make sure you create a new graph before the activity is created, and let the activity just use the existent graph.
How the activity access the graph? Well, I don't really love it, but we are used to access the application class (with explicit cast) and ask it to inject the dependencies for us. This is the way Dagger examples do it also.

Getting Dagger to inject mock objects when doing Espresso functional testing for Android

I've recently gone whole-hog with Dagger because the concept of DI makes complete sense. One of the nicer "by-products" of DI (as Jake Wharton put in one of his presentations) is easier testability.
So now I'm basically using Espresso to do some functional testing, and I want to be able to inject dummy/mock data to the application and have the activity show them up. I'm guessing since, this is one of the biggest advantages of DI, this should be a relatively simple ask. For some reason though, I can't seem to wrap my head around it. Any help would be much appreciated. Here's what I have so far (I've written up an example that reflects my current setup):
public class MyActivity
extends MyBaseActivity {
#Inject Navigator _navigator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.get(this).inject(this);
// ...
setupViews();
}
private void setupViews() {
myTextView.setText(getMyLabel());
}
public String getMyLabel() {
return _navigator.getSpecialText(); // "Special Text"
}
}
These are my dagger modules:
// Navigation Module
#Module(library = true)
public class NavigationModule {
private Navigator _nav;
#Provides
#Singleton
Navigator provideANavigator() {
if (_nav == null) {
_nav = new Navigator();
}
return _nav;
}
}
// App level module
#Module(
includes = { SessionModule.class, NavigationModule.class },
injects = { MyApplication.class,
MyActivity.class,
// ...
})
public class App {
private final Context _appContext;
AppModule(Context appContext) {
_appContext = appContext;
}
// ...
}
In my Espresso Test, I'm trying to insert a mock module like so:
public class MyActivityTest
extends ActivityInstrumentationTestCase2<MyActivity> {
public MyActivityTest() {
super(MyActivity.class);
}
#Override
public void setUp() throws Exception {
super.setUp();
ObjectGraph og = ((MyApplication) getActivity().getApplication()).getObjectGraph().plus(new TestNavigationModule());
og.inject(getActivity());
}
public void test_SeeSpecialText() {
onView(withId(R.id.my_text_view)).check(matches(withText(
"Special Dummy Text")));
}
#Module(includes = NavigationModule.class,
injects = { MyActivityTest.class, MyActivity.class },
overrides = true,
library = true)
static class TestNavigationModule {
#Provides
#Singleton
Navigator provideANavigator() {
return new DummyNavigator(); // that returns "Special Dummy Text"
}
}
}
This is not working at all. My Espresso tests run, but the TestNavigationModule is completely ignored... arr... :(
What am I doing wrong? Is there a better approach to mocking modules out with Espresso? I've searched and seen examples of Robolectric, Mockito etc. being used. But I just want pure Espresso tests and need to swap out a module with my mock one. How should i be doing this?
EDIT:
So I went with #user3399328 approach of having a static test module list definition, checking for null and then adding it in my Application class. I'm still not getting my Test injected version of the class though. I have a feeling though, its probably something wrong with dagger test module definition, and not my espresso lifecycle. The reason I'm making the assumption is that I add debug statements and find that the static test module is non-empty at time of injection in the application class. Could you point me to a direction of what I could possibly be doing wrong. Here are code snippets of my definitions:
MyApplication:
#Override
public void onCreate() {
// ...
mObjectGraph = ObjectGraph.create(Modules.list(this));
// ...
}
Modules:
public class Modules {
public static List<Object> _testModules = null;
public static Object[] list(MyApplication app) {
// return new Object[]{ new AppModule(app) };
List<Object> modules = new ArrayList<Object>();
modules.add(new AppModule(app));
if (_testModules == null) {
Log.d("No test modules");
} else {
Log.d("Test modules found");
}
if (_testModules != null) {
modules.addAll(_testModules);
}
return modules.toArray();
}
}
Modified test module within my test class:
#Module(overrides = true, library = true)
public static class TestNavigationModule {
#Provides
#Singleton
Navigator provideANavigator()() {
Navigator navigator = new Navigator();
navigator.setSpecialText("Dummy Text");
return navigator;
}
}
With Dagger 2 and Espresso 2 things have indeed improved. This is how a test case could look like now. Notice that ContributorsModel is provided by Dagger. The full demo available here: https://github.com/pmellaaho/RxApp
#RunWith(AndroidJUnit4.class)
public class MainActivityTest {
ContributorsModel mModel;
#Singleton
#Component(modules = MockNetworkModule.class)
public interface MockNetworkComponent extends RxApp.NetworkComponent {
}
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
MainActivity.class,
true, // initialTouchMode
false); // launchActivity.
#Before
public void setUp() {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
RxApp app = (RxApp) instrumentation.getTargetContext()
.getApplicationContext();
MockNetworkComponent testComponent = DaggerMainActivityTest_MockNetworkComponent.builder()
.mockNetworkModule(new MockNetworkModule())
.build();
app.setComponent(testComponent);
mModel = testComponent.contributorsModel();
}
#Test
public void listWithTwoContributors() {
// GIVEN
List<Contributor> tmpList = new ArrayList<>();
tmpList.add(new Contributor("Jesse", 600));
tmpList.add(new Contributor("Jake", 200));
Observable<List<Contributor>> testObservable = Observable.just(tmpList);
Mockito.when(mModel.getContributors(anyString(), anyString()))
.thenReturn(testObservable);
// WHEN
mActivityRule.launchActivity(new Intent());
onView(withId(R.id.startBtn)).perform(click());
// THEN
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 0))
.check(matches(hasDescendant(withText("Jesse"))));
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 0))
.check(matches(hasDescendant(withText("600"))));
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 1))
.check(matches(hasDescendant(withText("Jake"))));
onView(ViewMatchers.nthChildOf(withId(R.id.recyclerView), 1))
.check(matches(hasDescendant(withText("200"))));
}
Your approach doesn't work because it only happens once, and as Matt mentioned, when the activity's real injection code runs, it will wipe out any variables injected by your special object graph.
There are two ways to get this to work.
The quick way: make a public static variable in your activity so a test can assign an override module and have the actual activity code always include this module if it's not null (which will only happen in tests). It's similar to my answer here just for your activity base class instead of application.
The longer, probably better way: refactor your code so that all activity injection (and more importantly graph creation) happens in one class, something like ActivityInjectHelper. In your test package, create another class named ActivityInjectHelper with the exact same package path that implements the same methods, except also plusses your test modules. Because test classes are loaded first, your application will execute with the testing ActivityInjectHelper. Again it's similar to my answer here just for a different class.
UPDATE:
I see you've posted more code and it's close to working, but no cigar. For both activities and applications, the test module needs to be snuck in before onCreate() runs. When dealing with activity object graphs, anytime before the test's getActivity() is fine. When dealing with applications, it's a bit harder because onCreate() has already been called by the time setUp() runs. Luckily, doing it in the test's constructor works - the application hasn't been created at that point. I briefly mention this in my first link.
The call to getActivity will actually start your activity calling onCreate in the process which means you won't be getting your test modules added to the graph in time to be used. Using activityInstrumentationTestcase2 you can't really inject properly at the activity scope. I've worked around this by using my application to provide dependencies to my activities and then inject mock objects into it which the activities will use. It's not ideal but it works. You can use an event bus like Otto to help provide dependencies.
EDIT: the below in post form http://systemdotrun.blogspot.co.uk/2014/11/android-testing-with-dagger-retrofit.html
To test an Activity using Espresso + Dagger I have done the below
Inspired by the answer from #user3399328 I have a DaggerHelper class inside my Application class, which allows the test case to override the #Providers using Test #Modules which supply mocks. As long as
1) This is done before the testCases getActivity() call is made (as my inject call happens in my activity inside Activity.onCreate)
2) tearDown removes the test modules from the object graph.
Examples below.
Note: this is not ideal as this is subject to similar pitfalls of using factory methods for IoC but at least this way its only ever a single call in tearDown() to bring the system under test back to normal.
The DaggerHelper inside my Application class
public static class DaggerHelper
{
private static ObjectGraph sObjectGraph;
private static final List<Object> productionModules;
static
{
productionModules = new ArrayList<Object>();
productionModules.add(new DefaultModule());
}
/**
* Init the dagger object graph with production modules
*/
public static void initProductionModules()
{
initWithModules(productionModules);
}
/**
* If passing in test modules make sure to override = true in the #Module annotation
*/
public static void initWithTestModules(Object... testModules)
{
initWithModules(getModulesAsList(testModules));
}
private static void initWithModules(List<Object> modules)
{
sObjectGraph = ObjectGraph.create(modules.toArray());
}
private static List<Object> getModulesAsList(Object... extraModules)
{
List<Object> allModules = new ArrayList<Object>();
allModules.addAll(productionModules);
allModules.addAll(Arrays.asList(extraModules));
return allModules;
}
/**
* Dagger convenience method - will inject the fields of the passed in object
*/
public static void inject(Object object) {
sObjectGraph.inject(object);
}
}
My Test module inside my test class
#Module (
overrides = true,
injects = ActivityUnderTest.class
)
static class TestDataPersisterModule {
#Provides
#Singleton
DataPersister provideMockDataPersister() {
return new DataPersister(){
#Override
public void persistDose()
{
throw new RuntimeException("Mock DI!"); //just a test to see if being called
}
};
}
}
Test method
public void testSomething()
{
MyApp.DaggerHelper.initWithTestModules(new TestDataPersisterModule());
getActivity();
...
}
Tear down
#Override
public void tearDown() throws Exception
{
super.tearDown();
//reset
MyApp.DaggerHelper.initProductionModules();
}

how can i persist a model between multiple activities in android?

I'm a beginner to android development, and I'm trying to write my code in an MVC pattern, but I'm having trouble understanding how a model would work. As far as I can tell every time you start a new activity with an intent you are not able to pass a model along with it. As far as i can tell you'd have to reinitialize it each time you start a new activity. Am I missing something? I looked into Parcelable, but it seems that you loose your methods if you make your model Parcelable. right now I'm building a log in system, which checks my local sqllite db on start up if the user has already logged in, and if so it passes to another activity, otherwise it passes to the log in activity, but I wan't to keep that user model alive through all the activities. Is thee a way to do that?
You might want to also consider keeping a static reference around to the model data that you want to share across activities so that you don't have to keep serializing/deserializing the model when switching between activities. You can get away with using Parcelable if your models are small, but at some point, performance may become an issue.
I'm working on a project where we keep the models in a Singleton that we can access throughout the app, and although I generally hate Singleton's for how they can make unit testing more difficult, I have found this approach to perform better with larger models than trying to rely on Android's serialization mechanism.
Here's is a very rough example of what I mean (disclaimer: I have not actually run tested this code, but I hope this illustrates the concept):
You might have a singleton class that I terribly called Models
public class Models {
private static Models instance;
private boolean isInitialized = false;
private User user;
private OtherInterestingModel otherInterestingModel;
private Models() {
}
public static synchronized Models getInstance() {
if (instance == null) {
instance = new Models();
}
return instance;
}
public void loadModels() {
if (!isInitialized) {
/*
* One-time model initialization here.
*/
isInitialized = true;
}
}
public User getUser() {
return user;
}
public OtherInterestingModel getOtherInterestingModel() {
return otherInterestingModel;
}
}
In your LoginActivity, you can initialize the Models class, say, in your onCreate():
public class LoginActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Models.getInstance().loadModels();
User user = Models.getInstance().getUser();
OtherInterestingModelData otherData = Models.getInstance().getOtherInterestingModel();
// Do something with the model data...
}
/*
* This might be called after the user enters data and clicks a login button...
*/
private void login() {
startActivity(new Intent(this, AwesomeLoggedInActivity.class));
}
}
Once the user successfully logs into your app, you could have basically the same code in your main activity:
public class AwesomeLoggedInActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Models.getInstance().loadModels();
User user = Models.getInstance().getUser();
OtherInterestingModelData otherData = Models.getInstance().getOtherInterestingModel();
// Do something with the model data...
}
}
Notice that by having a Singleton, you avoided having to serialize the model data by passing it through the intent that started the main activity.
Yes, you can do that with the Parcelable interface.
You do not lose your class's methods when you implement the Parcelable interface. The interface simply defines a method for writing your member variables to a Parcel object when you need to pass the object around.
Once you retrieve the data from your Intent via getParcelableExtra(), the object is recreated from the Parcel and you can once again treat it as an instance of whatever class it is.
For example, if you have a User class that extends Parcelable, you can bundle it with an Intent by calling putExtra("user", myUser). myUser is then (behind the scenes) packed into a Parcel and attached to the Intent. In your next Activity, you can retrieve that User object with User myUser = (User) getParcelableExtra("user");, and the Parcel will be unpacked and returned to you. You wil once again have a fully functioning User object.

Categories

Resources