Extending the Intent class ... received ClassCastException
I am attemptin开发者_如何学Pythong to create an enhanced Intent
class (I call it DataIntent
) by giving it the ability to hold a "payload" of type Object (versus using it's built-in facility for Uri
's). DataIntent
extends Android's Intent
class.
My Activity
creates the extended object without any problems and the invocation of the startActivityForResult()
goes off without any problems also. But, in my responding Activity
when I call the getIntent()
method, and attempt to cast it to my DataIntent
, I'll throw the ClassCastException
.
I realize this is probably a very dumb question - a 1,000 appologies in advance - but does anyone know why I cannot cast it to the DataIntent
since that's what was used to start the new Activity
, and DataIntent
is a child of Intent
?
DataIntent dataIntent = (DataIntent)getIntent();
// invoked inside the responding Activity instance - throws a ClassCastException
You can't do that, sorry. You need to place your data inside of the Intent. The Intent object is moved across processes and thus the one you get back is not the same instance as the one you created.
I did the same thing CirrusFlyer. I also looked for the final keyword before I started to implement it. Google should mark Intent class as final.
You can and should extend an Intent, but you must understand the purpose of an Intent.
#1 an intent must be parcelable to support persisting the intent-data across an app restart (collapsed due to memory limitations, trimMemory etc).
#2 Understand that the Intent constructed by the caller, is not the Intent provided to the activity. This is due to item #1. So any object references would be lost and are a bad idea -- it needs to be parcelable remember.
#3 Intents should only contain data-context for the activity (or whatever). So you should not place pages of data into an intent, rather, it should contain ids or keys, or whatever contextual data is necessary to re-obtain the data for the activity (or whatever).
Now... Why should you extend an Intent? For good contracts!
Intents by themselves are terrible contracts, way too loose. Some people create static method helpers but there is a better way.
If an ABCActivity requires "A" "B" and "C" to perform properly. A generic intent cannot describe that, we'd rely on documentation that no one will read.
Instead we can create a ABCIntent whose constructor demands A,B & C. This creates a clear contract on what is required to load the activity. We can do that with a static method, but a an ABCIntent can also provide getters for A B C making it a clean packaged contract for describing requirements to load the activity and how to obtain the data.
There is one caveat, we need a private constructor to construct our ABCIntent from a generic intent to inherit the extras.
public ABCActivity extends Activity {
private ABCIntent intent;
public static ABCIntent extends Intent {
private ABCIntent(Intent intent) {
super(intent);
}
public ABCIntent(A a, B b, C c) {
putExtra("EXTRA_A", A.serialize(a));
putExtra("EXTRA_B", B.serialize(b));
putExtra("EXTRA_C", C.serialize(c));
}
public A getA() { return A.deserialize(getExtra("EXTRA_A")); }
public B getB() { return B.deserialize(getExtra("EXTRB_B")); }
public C getC() { return C.deserialize(getExtra("EXTRC_C")); }
}
@Override
protected ABCIntent getIntent() {
return intent == null ? (intent = new ABCIntent(super.getIntent())) : intent;
}
@Override
protected void onCreate( ... ) {
A a = getIntent().getA();
B b = getIntent().getB();
C c = getIntent().getC();
// TODO: re-obtain activity state based on A, B, C then render
}
}
Notice that we construct ABCIntent from intent. The ABCIntent inherits the intent extras.
Now you have a nicely packaged class who's job it is to define the contract for the activity and to provide the contractual data to the activity.
If you're a new engineer on the project, there is no way for you to misunderstand how to use this. No docs to read.
精彩评论