ClassCastException on custom object with child objects which is parcelable - java

Good day,
I was assigned to an android project inside my company and I'm having a little bit of a struggle. I have not touched Android in a few years. Figured you might be able to help me find what i am missing.
I have a project that calls an external libratry for reading a barcode, then the code does a parsing of the byte array and converts it into an object. The problem I am having is of comunication between my MainActivity and the activity that scans the barcode.
This is the piece of code that calls my barcode reader activity:
setContentView(R.layout.activity_main);
MyObjectActivity.setParentActivity(this);
Intent intent = new Intent(this, MyObjectActivity.class);
startActivityForResult(intent, 0);
This one should escalate the scanned data from MyObjectActivity object into my MainActivity (so i can actually do something with the data).
try
{
//MyObject objet contains child objects
MyObject content = MyObjectParser.retrieveContentData(data /*contains the byte array*/);
Intent data_toreturn = new Intent();
data_toreturn.putExtra("data_sent", true);
data_toreturn.putExtra(BARCODE_DATA_EXTRA_TAG, content);
if (getParent() == null)
{
setResult(RESULT_OK, data_toreturn);
} else
getParent().setResult(RESULT_OK, data_toreturn);
} catch(final RuntimeException e)
{
parentActivity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
Toast.makeText(parentActivity, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
// stop the Activity
finish();
While debugging i manage to run all the code up until the finish(). Then i get the exception
Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { (has extras) }} to activity {MyObjectActivity}: java.lang.ClassCastException: java.lang.Object[] cannot be cast to ChildObject[]
According to what I remember from developping in android, in order to be able to pass Objects between Activities you need intents and Objects that are Parcelable or Serializable (not sure about this one). I've reviewed the code and the sub objects DO implement this.
I really don't know how to continue. It is either a thing of configuration, or I am doing something very wrong and I am not seeing it.
Thank you for your response.

So I see you are using
startActivityForResult(intent, Yournumber) //I would not use 0, use 1001 or something more custom.
so that you make yourself the parent of the launched activity.
So why are you doing the setParentActivity call? I assume just for doing your Toast? Seems like a unhealthy way to handle that, but that is a different issue.
Then override onActivityResult in that parent activity to handle the intent data returned. As I'm sure you have already done.
But I'm not certain of your "content" object if it is parcable or not. You can check by simply commenting out "adding that to the intent" and seeing if it gets delivered when that object is not inside the intent.
If it is delivered then you should ensure that your object implements Parceable so that it can be put in the intents. If it still does not get delivered then it would appear you are having an issue with your parent not pointing to the correct class somehow and we would need to see more code to help out on that.
I see you are passing the raw bytes, which should work fine, but you could try a wrapper object that implements parceable as well that holds the bytes as a member and pass back that object as a last ditch effort as well.

Let's assume you're sending an Object X via an explicit Intent from Activity A to Activity B.
Step 1 - make sure your class X implements Serializable interface (which you said you already have). Also make sure that all other objects inside your Object X do implement Serializable interface.
Step 2 - Somewhere inside your Activity A you'd have similar code:
X objectX = new X();
Intent intent = new Intent(A.this, B.class);
intent.putExtra("myObject", objectX);
startActivity(intent);
Step 3 - Inside your Activity B you will get the Object reference and typecast it to X:
Intent intent = getIntent();
X objectX = (X)intent.getSerializableExtra("myObject");
Hope this helps. This is the basic pattern of passing objects between Activities and there is nothing more to it.

Related

Which is considered better to pass information between Activities on Android project, send a model or only an id?

I have an android app and I have 3 screens that the user must fill some fields. Each screen have 7 fields to be filled. At the end of the process, I submit the information to the server using Retrofit with an API.
This is how I pass the information between Activities in my first project
// first activity
AutoDados autuacaoDados = new AutoDados(... a lot of parameters ...);
Intent intent1 = new Intent(AutoInf_Lista_Generica.this, AutoInf_Menu.class);
intent1.putExtra("PARAM_ENV_DADOS", autuacaoDados);
startActivity(intent1);
// second activity
Bundle extras = intent.getExtras();
if (extras == null) {
return "";
}
AutoDados autuacaoDados = (AutoDados) extras.getSerializable("PARAM_ENV_DADOS");
I have another project that I use the following code to pass data between activities.
// first activity
Intent intent1 = new Intent(AutoInf_Lista_Generica.this, AutoInf_Menu.class);
intent1.putExtra("ID_AUTOS", myId);
startActivity(intent1);
// second activity
intent.getIntExtra("ID_AUTOS", 0);
// code that recover the data from a SQLite database based in the "ID_AUTOS"
These both ways I was able to recover data between activities, but which way is considered better and why is it better?
Another question, is there a better way to pass data between activities ?
If possible, talk about the pros and cons about each approach.
The main difference between the tow ways is that in the first method you are passing an Object to the second activity while in the second method you are passing a primitive type.
which is better ? each way has its own use case, there is no better way, it depends on your use case

Confirmation on my Understanding of Beginning Android Concept (Using Multiple Activities)

I am a beginner at android development, and have reached the end of Building your First App. Before I move on, I would like to confirm and validate my understanding of using multiple activities and communicating from one activity to another.
/** Called when the user clicks the Send button */
public void sendMessage(View view) {
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.edit_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity(intent);
}
1) Is my understanding correct that the second paramater in the constructor for Intent (Intent intent = new Intent(this, DisplayMessageActivity.class)) serves as a reference for startActivity(...) and reflection is used to call the method onCreate() in the class DisplayMessageActivity since the class DisplayMessageActivity was given as a class object?
2) What is the use of the first paramater (the context one in the constructor)? (Basically how does Android use the first parameter, a brief description please, to start the activity)?
3) As seen in the tutorial, last part of building your first app, it advises me to declare a variable as such: (public final static String EXTRA_MESSAGE = "me.marshac.myfirstapp.MESSAGE";). I know the purpose of this declaration and initialization, but why don't I have to specify the full package name (me.marshac.myfirstapp. (...) .MESSAGE) and where is the MESSAGE variable coming from? The only two variables similar to that are both local variables in sendMessage() and the other activity's onCreate(), but they are different case and local?
I am sorry for the very in-depth inquiries, I want to establish a firm understanding of the beginner concepts before I move on to intermediate/advanced ones.
1) Yes. I think that's what is happening behind the scenes. If you want to know exactly how they did it, you can go to read the Android OS source code. It is open source, you know. Just Google it!
2) Android uses a stack for storing activities. When you first started your app, it's like this:
MyActivity
Then when you start another activity, a new activity object is pushed onto the stack
DisplayMessageActivity
MyActivity
When you tap the back button, an activity from the stack is popped.
If you didn't give this as the parameter, how would the OS know where to push the new activity onto?
3) I think this is just a convention of some kind. I usually use simple names like message, and it works! It's similar to asking why should I name a class in PascalCase and a local variable in camelCase?

Intent putExtra(String,String) inside of AsyncTask

I'm simply trying to carry a string onto the next activity without having to define an entire object for the task. I've seen similar solutions and gotten them to work BUT without using AsyncTask to create the intent.
protected void onPostExecute(Boolean result) {
if (loggedIn && hasPin) {
Intent intent = new Intent(UniteActivity.this,
WebViewActivity.class);
intent.putExtra(PASSED_USERNAME, passUser);
startActivity(intent);
}
if (loggedIn && !hasPin) {
Intent intent = new Intent(UniteActivity.this,
CreatePinActivity.class);
intent.putExtra(PASSED_USERNAME, passUser);
startActivity(intent);
PASSED_USERNAME is a public static constant to hold the package name, just as the putExtra() method requires. I then try to pull the value out in the next activity.
Intent extras = getIntent();
String username = extras.getStringExtra(UniteActivity.PASSED_USERNAME);
// carry username to next activity
Intent intent = new Intent(CreatePinActivity.this,WebViewActivity.class);
intent.putExtra(PASSED_USERNAME, username);
startActivity(intent);
There is never a String to pull out, the value of username is always null. I've gone through the debugger and found that the Eclipse IDE debugger shows different intent ID's between the activities, they are never consistant. Is it possible that AsyncTask is interfereing somehow because it splits into a seperate thread?
I don't know if this applies to your problem, because I can't see from your code snippet if the intermediary activity is freshly created or not.
BUT: the getIntent()-method always returns the first Intent that started the activity. If the activity remains in the background and receives a new Intent this value does not get updated automatically. You have to override onNewIntent(...) and manually call setIntent(...) for this to work (or do all your stuff directly there).
So just for the case that you do not run your posted code in the onCreate() method please check if you did not miss to fetch the real intent you are interested in.
Not sure of the exact answer for you solution.
You calling startActivity on the UI since it's in postExecute().
If all else fails you can just save that value to a sharedpreference.
The way you have handled the variable PASSED_USERNAME seems incorrect. You have used it in some palaces as simple PASSED_USERNAME whereas in some other places you have used it with the class named prefixed UniteActivity.PASSED_USERNAME. Since it is a Public Static Constant always use it prefixed with the class name.

Puzzling java.lang.NullPointerException in Android App

I'm currently working on an Android App and, almost every time I use it, I get a an error. Most of the time it doesn't crash the app, but it is still frustrating that I'm seeing this error. I thought I did a check for it, but I could be wrong. Thanks for the help! The relevant code is below. (It's relevant because the line outside the if statement is throwing the NullPointerException.)
Activity activity;
if(activity == null)
{
activity = new Activity();
}
Intent intent = new Intent(activity, Service.class);
You don't usually instantiate the Activity class in this manner. Please see the documentation on the Android Activity class here:
http://developer.android.com/reference/android/app/Activity.html
You should post some more of the surrounding code, but your problem is that creating new Intent requires a valid Context. Usually you create an Intent within an Activity (or Service or BroadcastReceiver) class so you can just do something like:
Intent intent = new Intent(this, Service.class);
Occasionally you'll create it somewhere else and pass it that valid Context, but you should pretty much never create an Activity by calling the constructor directly. There's a lot of other initialization necessary to make it useful.
As postet previously there is more to initiate for an activity than calling the constructor. Probably you get a null pointer exception deep within the Intent Constructer where it is trying to get some of the Activityinformation usually provided.
If you really want to create a Service, heres a link for starting a Service, but you should really read the whole article and probably some more of the activity lifecycle ressources.
http://developer.android.com/guide/topics/fundamentals/services.html#StartingAService

How to Invoke or call one app from another app in Android?

I want to invoke one application from another application.
My Java file code:
Intent intent = new Intent(Intent.ACTION_RUN);
intent.setComponent(new ComponentName("Package name", "class name"));
startActivity(intent);
But I'm getting problem in specifying exact package path and I don't know permission for that code in Manifest. Please, help me on this.
I am going to assume that you really mean that you want to launch another app, not another Activity in your app.
Then there are two ways to do this. You can try using an implicit intent which according to the docs, an (Implicit) intent is "an abstract description of an operation to be performed" that "provides for performing late runtime binding between code in different applications." Sort of like trying to launch a method over the wire using an interface. You cannot be sure exactly what the class of the object that is launched only that it can handle the action and categories that you declare.
The second approach is an explicit intent, which is more like making a concrete call over the wire. If you know the package and class name this should work.
Intent intent = new Intent(Intent.ACTION_MAIN);
//intent.putExtra("plain_text", "Testing");
intent.setClassName("packagename", "packagename.ClassName"); // Explicit Intent
try {
startActivity(intent);
}
catch (Exception e)
{
Log.d(TAG","onCreate",e);
}
}
You can add extra info using flags depending on your needs and where your are trying to launch from.
JAL
Starting an external activity from your app is done using a slightly different method to that which you are using. You need to create an intent with a given action. For example, launching an intent to fetch an image from the gallery would look like this:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, IMAGE_PICK);
Note that you don't explicitly define the activity to be loaded, rather the kind of action you want to perform. Android will then pick (or have the user pick) an activity that has registered to handle this kind of intent to be run.
You might need to be a little more specific about what you're doing. If all you want to do is, say, launch another Activity from your main Activity, something like this would work:
Intent intent = new Intent(this, OtherActivity.class);
intent.putExtra("key", "data"); //put any data you want to pass into the new activity
startActivity(intent);
Then just make sure you put the new activity in your manifest like this:
<activity android:name=".OtherActivity"
android:label="#string/other"/>
If your goal is something else then you should be ore specific with what you want to do.

Categories

Resources