I`m trying to parse an object from my my main activity to a new activity that starts when the user clicks a button. I've seached the internet and found how to parse primative types and custom made classes that implements parceble or serilizable, but can't find any information on how to transfeer a raw object.
I'll write psuedo-code of what I`m trying to achive below:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadConnectInfo();
View connectButton = findViewById(R.id.connectButton);
connectButton.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.connectButton:
Intent i = new Intent(this, NewClass.class);
Socket s = connect(); // this is the object I want to parse to to "NewClass"
startActivity( i);
break;
}
You can't pass an object that is neither serializable nor parcelable between activities this way. What you probably want to do in this case is make your code that manages and interacts with the socket into a service and bind to that service in all the activities that need to use it.
Sometimes when I had to pass variable from one class to another I've used static variables in class which I deliver some objects. This will work but it is not recommended way to pass object in Android and you don't have guaranty that will work always.. Here you should check if your delivered object is not null of course.
public void onClick(View v) {
switch (v.getId()) {
case R.id.connectButton:
Intent i = new Intent(this, NewClass.class);
Socket s = connect(); // this is the object I want to parse to to "NewClass"
//Here using static field of class you pass variable to NewClass
//You can access this value in NewClass like that: NewClass.StaticSocket
//Warning: This is not a standar android scheme but I tested and it works
//with Date object
NewClass.StaticSocket = s;
startActivity( i);
break;
}
On second activity:
public void onCreate(Bundle savedInstanceState) {
Log.i("StaticVar","NewClass.StaticSocket: "+ NewClass.StaticSocket.toString());
There are already other posts about this:
What's the best way to share data between activities?
BTW, be careful: objects like sockets are not meant to be shared by bundles through the intent because they shouldn't be serialized. Maybe using a global state, like a singleton does it for you.
Related
I'm trying to send an object created from the Spotify API (a SpotifyAppRemote instance) from my MainActivity class to a BackgroundService (implemented as IntentService).
Since I can't use parcelable to send my object as I have no control over the API I was trying to use GSON to send it via the putExtra method from my intent like this:
intent.putExtra("spotifyRemote", gson.toJson(mSpotifyAppRemote, SpotifyAppRemote.class));
However, on runtime I get an error:
java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: com.spotify.protocol.types.ImageUri. Forgot to register a type adapter?
Is there another way to send this object to my Service? Looking for this error message didn't really help.
Here's the code from my MainActivity class:
#Override
public void onConnected(SpotifyAppRemote spotifyAppRemote) {
mSpotifyAppRemote = spotifyAppRemote;
getCurrentTrack();
// Now you can start interacting with App Remote
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
infoText.setText("Successfully started!");
counter = 1;
numSongs = Integer.parseInt(mEdit.getText().toString());
PlayerApi playerApi = mSpotifyAppRemote.getPlayerApi();
playerApi.seekTo(0);
playerApi.resume();
Intent intent = new Intent(MainActivity.this, BackgroundService.class);
intent.putExtra("counter", counter);
intent.putExtra("numSongs", numSongs);
intent.putExtra("firstTrack", gson.toJson(curTrack, Track.class));
intent.putExtra("spotifyRemote", gson.toJson(mSpotifyAppRemote, SpotifyAppRemote.class));
startService(intent);
}
});
}
I worked around this by declaring a static variable in my Service and setting the variable in my MainActivity like this:
BackgroundService.mSpotifyAppRemote = mSpotifyAppRemote;
Declaration in my Service:
public static SpotifyAppRemote mSpotifyAppRemote = null;
How can I receive a custom ArrayList from another Activity via Intent? For example, I have this ArrayList in Activity A:
ArrayList<Song> songs;
How could I get this list inside Activity B?
The first part to understand is that you pass information from Activity A to Activity B using an Intent object, inside which you can put "extras". The complete listing of what you can put inside an Intent is available here: https://developer.android.com/reference/android/content/Intent.html (see the various putExtra() methods, as well as the putFooExtra() methods below).
Since you are trying to pass an ArrayList<Song>, you have two options.
The first, and the best, is to use putParcelableArrayListExtra(). To use this, the Song class must implement the Parcelable interface. If you control the source code of Song, implementing Parcelable is relatively easy. Your code might look like this:
Intent intent = new Intent(ActivityA.this, ActivityB.class);
intent.putParcelableArrayListExtra("songs", songs);
The second is to use the version of putExtra() that accepts a Serializable object. You should only use this option when you do not control the source code of Song, and therefore cannot implement Parcelable. Your code might look like this:
Intent intent = new Intent(ActivityA.this, ActivityB.class);
intent.putSerializableExtra("songs", songs);
So that's how you put the data into the Intent in Activity A. How do you get the data out of the Intent in Activity B?
It depends on which option you selected above. If you chose the first, you will write something that looks like this:
List<Song> mySongs = getIntent().getParcelableArrayListExtra("songs");
If you chose the second, you will write something that looks like this:
List<Song> mySongs = (List<Song>) getIntent().getSerializableExtra("songs");
The advantage of the first technique is that it is faster (in terms of your app's performance for the user) and it takes up less space (in terms of the size of the data you're passing around).
Misam is sending list of Songs so it can not use plain putStringArrayList(). Instead, Song class has to implement Parcelable interface. I already explained how to implement Parcelable painless in post here.
After implementing Parcelable interface just follow Uddhavs answer with small modifications:
// First activity, adding to bundle
bundle.putParcelableArrayListExtra("myArrayListKey", arrayList);
// Second activity, reading from bundle
ArrayList<Song> list = getIntent().getParcelableArrayListExtra("myArrayListKey");
I hope this helps you.
1. Your Song class should be implements Parcelable Class
public class Song implements Parcelable {
//Your setter and getter methods
}
2. Put your arraylist to putParcelableArrayListExtra()
public class ActivityA extends AppCompatActivity {
ArrayList<Song> songs;
#Override
protected void onCreate(Bundle savedInstanceState) {
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getApplicationContext(), ActivityB.class)
.putParcelableArrayListExtra("songs", (ArrayList<? extends Parcelable>) songs));
}
});
}
3. In the ActivityB
public class ActivityB extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
final ArrayList<Song> songs = intent.getParcelableArrayListExtra("songs");
//Check the value in the console
buttonCheck.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for (Song value : songs) {
System.out.println(value.getTitle());
}
}
});
}
to send a string arrayList in Java you can use,
intent.putStringArrayListExtra("key", skillist <- your arraylist);
and
List<String> listName = getIntent().getStringArrayListExtra("key");
Please note, bundle is one of the key components in Android system that is used for inter-component communications. All you have to think is how you can use put your Array inside that bundle.
Sending side (Activity A)
Intent intent1 = new Intent(MainActivity.this, NextActivity.class);
Bundle bundle = new Bundle();
Parcelable[] arrayList = new Parcelable[10];
/* Note: you have to use writeToParcel() method to write different parameters values of your Song object */
/* you can add more string values in your arrayList */
bundle.putParcelableArray("myParcelableArray", arrayList);
intent1.putExtra("myBundle", bundle);
startActivity(intent1);
Receiving side (Activity B)
Bundle bundle2 = getIntent().getBundleExtra("myBundle"); /* you got the passsed bundle */
Parcelable[] arrayList2 = bundle.getParcelableArray("myParcelableArray");
this is my first question being asked on stackoverflow. My question is regarding variable use across different recyclable intents.
e is declared like this.
final Bundle e=getIntent().getExtras();
Here i am creating new intents for different setOnClickListener() and passing a different variable for each intent.
Intent info = new Intent(EItemListView.this, ItemInfo.class);
Bundle extras = new Bundle();
int[] a=new int[listview.getAdapter().getCount()];
if (i == 0) {
extras.putIntArray("img", n5x_images);
extras.putString("info", n5x_info);
extras.putInt("pc",a[0]);
} else if (i == 1) {
extras.putIntArray("img", op3_images);
extras.putString("info", op3_info);
extras.putInt("pc",a[1]);
}
info.putExtras(extras);
startActivity(info);
Now this is the OnClickListener() where i am trying to update the variables which i passed through the intent extras, but am unable to update those variables.
addtc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int c=e.getInt("pc");
c=c+1;
Log.i("Log","value "+c);
}
The log message which i get from the above method is always 1, i think the variable in c is always set to 0 and then increments by 1 and hence the log message shows 1.
I need the variables a[0],a[1],a[2], etc to pertain its increment operation.
To make it more clear, this is the java file i am using. The error is in the OnClickListener of addtc button at the bottom of this code.
public class ItemInfo extends AppCompatActivity {
private ViewAnimator viewanimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_info);
Button next=(Button)findViewById(R.id.bnext);
Button prev=(Button)findViewById(R.id.bprev);
viewanimator=(ViewAnimator)findViewById(R.id.viewAnimator);
TextView info=(TextView)findViewById(R.id.item_info);
Button addtc=(Button)findViewById(R.id.badd);
Button test=(Button)findViewById(R.id.button);
Bundle e=getIntent().getExtras();
int img[]=e.getIntArray("img");
for(int i=0;i<img.length;i++)
{
ImageView imgview = new ImageView(getApplicationContext());
imgview.setImageResource(img[i]);
viewanimator.addView(imgview);
}
info.setText(e.getString("info"));
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewanimator.showNext();
}
});
prev.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewanimator.showPrevious();
}
});
addtc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int c=e.getInt("pc");
c=c++;
Log.i("Log","value "+c);
}
});
}
}
Thanks in advance!!!
Your approach is wrong. You cannot do this in this way. Your understanding of what an "extra" in an Intent is incorrect.
When you do this:
extras.putInt("pc",a[1]);
This adds an "extra" to the extras Bundle. The Bundle is simply a key/value pair map and you have added an entry that contains the key "pc" and the value is whatever a[1] is. It puts a copy of the value of a[1] into the Bundle, it does not put a reference to a[1] in the Bundle.
Therefore, if a[1] is 5 when you add it to the extras Bundle, a[1] will always be 5 and will never be changed to anything else.
You can't do this in this way.
Alternative: Depending on your application architecture and what you are trying to do, you can use one of the following methods:
1) Use startActivityForResult(), pass the data from one Activity to another, have the second Activity update the data and put it back into the Intent which is then returned to the "calling" Activity by using setResult().
2) Use a static variable (basically a "global" variable) to contain the data. Both activities can then access the data directly (you don't need to put the data in the Intent.
3) Put the data in a database. Both activities can then read/write from/to the database.
First advice I can give you is debugging and posting debug result. for example, are you sure that a[0] and a[1] aren't 0?
Assuming they are not, why are you declaring the bundle as final? referring to this probably final is not what you were looking for. Try removing it or replacing with private
Another suggestion is more for readable purpose, replace c = c+1; with c++; but this doesn't change the result, it just make it more linear and easier for reading.
Now after this fix (the final keyword one) tell me if something changed please :)
I have creted a program that has 3 Activities: MainActivity, UpgradeActivity and UpgradesActivity.
Main Activity contains a timer and it also contains an instance of a Vehicle class.
public class MainActivity extends Activity {
TextView vehicleSpeed, vehicleName, vehicleDistance, vehicleLocation,
vehicleStatus, vehicleNews, vehicleInfo, vehicleMoney;
ProgressBar vehicleFuel;
public static Vehicle vehicle;
boolean launched;
public static PartType selectedType;
Handler handler = new Handler();
I have a button in MainActivity, that when pressed will take me to a page where i can select which part of the vehicle i wish to upgrade. For example i select: Engine. The engine Button takes me to the Upgrade Activity. In this activity i can buy the upgrade which should be applied to the vehicle in MainActivity. For the purpose of this question, lets say it set vehicles speed to +3.
My question is in regards to how to access the vehicle instance inside the MainActivity from the UpgradeActivity. I've tried making the instance static but that didn't work. How do i gain access and how can i change the vehicles variables from the other activities.
Here is where i am making the instance:
#Override
protected void onCreate(Bundle savedInstanceState) {
this.selectedType = PartType.Antenna;
this.launched = false;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vehicle = new Vehicle();
vehicle.setupCar();
Here is where i am accessing the variable in Upgrades, it call the upgrade function inside of the Vehicle Class:
buyUp1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MainActivity.vehicle.upgradeEngine(MainActivity.vehicle.engineLvl + 1);
Intent activityChangeIntent = new Intent(UpgradesActivity.this, MainActivity.class);
UpgradesActivity.this.startActivity(activityChangeIntent);
}
});
And this is the function within the Vehicle Class:
public void upgradeEngine(int lvl) {
engineLvl += 3;
engine = parts.getEngine(lvl);
}
The vehicle Stores an integer called: EngineLvl. This determines what level the cars engine is. The level is incremented by +3 everytime the engine is updated.
The problem is that the engine level never changes. Even if i make the Vehicle instance and all of the variables within vehicle STATIC;
MAINACTIVITY:
Vehicle
Button to UpgradesActivity
UPGRADESACTIVITY:
Button to UpgradeActivity
UPGRADEACTIVITY:
Change vehicle enginelvl Int
Button back to MainActivity
Main>Upgrades>Upgrade
Thank you for your time
Hard to say what is wrong without seeing the code, but I would advise you to use the Intent extras to move your data between activities. You will need to make your Vehicle class implement Parcelable (there is an example of how to implement Parcelable on that page, and countless others on the net). You pass your object as extra to the intent launching your UpgradeActivity like this :
Intent upgradeIntent = new Intent(this, UpgradeActivity.class);
upgradeIntent.putExtra("com.example.model.Vehicle", yourVehicleObject);
startActivityForResult(upgradeIntent, UPGRADE_CAR_REQUEST_CODE);
//UPGRADE_CAR_REQUEST_CODE is a unique private static final int
Then you can retrieve it in your UpgradeActivity onCreate method :
Intent intent = getIntent();
Vehicle vehicleFromLastActivity = intent.getParcelableExtra("com.example.model.Vehicle");
Before going back to your MainActivity you do something like this :
Intent dataIntent = new Intent();
dataIntent.putExtra("com.example.model.Vehicle", yourModifiedVehicleObject);
setResult(RESULT_OK, dataIntent);
finish();
Then finally in MainActivity you need to handle the result, it is done like this :
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case UPGRADE_CAR_REQUEST_CODE:
if(resultCode == android.app.Activity.RESULT_OK) {
Vehicle modifiedObject = data.getParcelableExtra("com.example.model.Vehicle");
// Now you can use that object which is coming from UpgradeActivity
}
}
}
Of course this could cause issues if your Vehicle class takes a lot of memory. You could then consider passing only the relevant information through the Intent to rebuild the object in the UpgradeVehicle Activity, for example only the id & name.
As the title says I want to transfer data, in this case the information introduced by the user on an EditText and a Spinner, from one activity to another.
I am following a tutorial from a book but it doesn't work (I think its not complete). Here the code of the program:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
this.location=(EditText)findViewById(R.id.location);
this.cuisine=(Spinner)findViewById(R.id.cuisine);
this.grabReviews=(Button)findViewById(R.id.get_reviews_button);
ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.cuisine, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
this.cuisine.setAdapter(adapter);
this.grabReviews.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
handleGetReviews();
}
}
);
}
private void handleGetReviews() {
RestaurantsActivity application= (RestaurantsActivity) getApplication();
application.setReviewCriteriaCuisine(this.cuisine.getSelectedItem().toString());
application.setReviewCriteriaLocation(this.location.getText().toString());
Intent intent=new Intent(Constants.INTENT_ACTION_VIEW_LIST);
startActivity(intent);
}
This code above doesn't work. I dont understand four things:
-RestaurantsActivity must be the actual activity right?
-In all the examples I have seen over the internet there is an application extends class, in this example there isnt.
-setReviewCriteria function is missing
-Where does Constants.INTENT_ACTION_VIEW_LIST come from ?
So your target is to get the data to Restaurantsactivity?
Normally data in android are handed over from one activtiy to another by using Intents.
So first you create an intent.
Then you put the data you want to transfer into the intent by using the intent.putExtra() method.
In the activity that gets the intent you can get the data by using getIntent().getExtra() method (getExtra can be something like getStringExtra()).
Here is a small example for a edit box called "name":
public void onCreate(Bundle iBundle){
//do some stuff here
//perhaps define some Buttos and so on
//now lets start the activity
Intent intent = new Intent(currentActivityname.this, ActivityYouWantToStart.class);
intent.putExtra("name", name.getText().toString())
startActivity(intent); // you can also start an startActivityForResult() here :)
}
In our receiving activity you can now handle the intent (e.g. in the onCreate() method
public void onCreate(Bundle iBundle){
String name = this.getIntent().getStringExtra("name",some default value);
}
Try to put data in the Bundle and start Activity with this Bundle
Intent intent = new Intent(this, YourSecondActivity.class);
intent.putExtra(... HERE YOUR BUNDLE WITH DATA ...);
startActivity(intent);
Hope, it help you!