Passing class ArrayList between intents - java

I've created a class named "Player".
public class Player{
public String name;
public int score;
}
Everytime I click a button a new TextView is generated and also a new Player class. This is the code:
private TextView createNewTextView (String text){
final LayoutParams lparams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
final TextView newTextView = new TextView(this);
newTextView.setLayoutParams(lparams);
newTextView.setText(text);
Player newPlayer = new Player();
newPlayer.name = text;
newPlayer.score = 0;
players.add(newPlayer);
zacniIgro.putExtra("players", (ArrayList<Player>) players);
return newTextView;
}
Is this the right way to do it? I think there is a small flaw because each time a button is clicked, a new Player is added under the label of "newPlayer". How do I fix this?
And my main problem is this; how do I "unpack" the ArrayList in the second activity so that I can then manipulate with each element of the ArrayList? I tried getStringArrayListExtra() but it doesn't work. I also tried getExtras() but that also doesn't work since it retrieves a bundle. Or is that the right way? But what do I do with the bundle then?

The "label" newPlayer is only the name of a local variable which is always a different thing each time the method is run, so no problem here.
When you call putExtra() here players is interpreted as Serializable so corresponding call is getSerializableExtra("players"). Result must then be casted to an ArrayList<Player>.
To make this work you must additionally make Player class serializable. Here you can just implement interface Serializable.

The better way to do this is with Parcelable.
Simple example:
public class Device implements Parcelable {
private String name;
private String hash;
/**
* Default private constructor.
*/
public Device() {
}
public Device(final Parcel parcel) {
super();
readFromParcel(parcel);
}
public static final Parcelable.Creator<Device> CREATOR = new Parcelable.Creator<Device>() {
#Override
public Device createFromParcel(final Parcel source) {
return new Device(source);
}
#Override
public Device[] newArray(final int size) {
return new Device[size];
}
};
#Override
public int describeContents() {
return hashCode();
}
#Override
public void writeToParcel(final Parcel parcel, final int flags) {
parcel.writeString(name);
parcel.writeString(hash);
}
private void readFromParcel(final Parcel parcel) {
this.name = parcel.readString();
this.hash = parcel.readString();
}
Put your object in intent like this:
intent.putParcelableArrayListExtra("Key", YourObject);
To Get in another screen:
Intent intent = getIntent();
intent.getParcelableArrayExtra("key");

Related

How to pass entire Arraylist to another activity

I am making a mp3 player app , in my main activity I am showing the list of all songs in recycler view and when user click on the song I am trying to send entire array list of songs to my player activity , where I can work for with next and previous songs play , but my app crashes when click the song
Process: com.choudhary.musicplayer, PID: 8686
java.lang.RuntimeException: Parcel: unable to marshal value com.choudhary.musicplayer.AudioModel#a0de380
at android.os.Parcel.writeValue(Parcel.java:1667)
at android.os.Parcel.writeList(Parcel.java:966)
at android.os.Parcel.writeValue(Parcel.java:1614)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:878)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1588)
at android.os.Bundle.writeToParcel(Bundle.java:1233)
at android.os.Parcel.writeBundle(Parcel.java:918)
at android.content.Intent.writeToParcel(Intent.java:9987)
at android.app.IActivityManager$Stub$Proxy.startActivity(IActivityManager.java:3636)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1675)
at android.app.Activity.startActivityForResult(Activity.java:4651)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:597)
at android.app.Activity.startActivityForResult(Activity.java:4609)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:583)
at android.app.Activity.startActivity(Activity.java:4970)
at android.app.Activity.startActivity(Activity.java:4938)
at com.choudhary.musicplayer.MusicAdapter$1.onClick(MusicAdapter.java:54)
at android.view.View.performClick(View.java:6608)
at android.view.View.performClickInternal(View.java:6585)
at android.view.View.access$3100(View.java:785)
at android.view.View$PerformClick.run(View.java:25921)
My Adapter's OnBind method :--
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.name.setText(arrayList.get(position).getaName());
holder.album.setText(arrayList.get(position).getaAlbum());
holder.imageView.setImageBitmap(BitmapFactory.decodeFile(arrayList.get(position).getAlbumart()));
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent in = new Intent(context,PlayerActivity.class);
in.putExtra("SONG",arrayList.get(position).getaName());
in.putExtra("PATH",arrayList.get(position).getaPath());
in.putExtra("ALBUM",arrayList.get(position).getaAlbum());
in.putExtra("LIST",arrayList);
in.putExtra("POSITION", arrayList.get(position).toString());
context.startActivity(in);
}
});
}
my Player Activity :---
public class PlayerActivity extends AppCompatActivity {
TextView songanme, songAlbum,duration,movetime;
ImageView playbutton,nextbtn,previousbtn;
SeekBar seekBar;
MediaPlayer mediaPlayer ;
ArrayList<AudioModel> list;
int CURRENT_POSITION ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
songanme = findViewById(R.id.music_name_pl);
movetime = findViewById(R.id.move_time);
seekBar = findViewById(R.id.seekBar);
songAlbum = findViewById(R.id.music_album_pl);
duration = findViewById(R.id.duration);
playbutton = findViewById(R.id.play_btn_pl);
nextbtn = findViewById(R.id.next_btn_pl);
previousbtn = findViewById(R.id.previous_pl);
list = new ArrayList<>();
songanme.setSelected(true);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
list = (ArrayList) bundle.getParcelableArrayList("LIST");
}
Let's assume that you want to pass an ArrayList of the Song class from Activity1 to Activity2.
1- The Song class should implement the Serializable class.
It would be something like that..
import java.io.Serializable;
public class Song implements Serializable {
String name;
String album;
public Song(String name, String album) {
this.name = name;
this.album = album;
}
}
2-In Activity1 pass your array list object as an extra to Ativity2
ArrayList<Song> songs= new ArrayList();
songs.add(new Song("song1","album1"));
songs.add(new Song("song2","album2"));
songs.add(new Song("song3","album3"));
Intent intent=new Intent(this,Activity2.class);
intent.putExtra("songs",songs);
startActivity(intent);
3- Finally receive the array list with getSerializableExtra in Activity2
ArrayList<Song> songs = (ArrayList<Song>) getIntent().getSerializableExtra("songs");
Log.i("HINT", "" + songs.size());
You can create a singleton class for sharing your ArrayList across various components of android. Sample code for the singleton class is described below-
public class SongBank
{
private static SongBank instance;
private ArrayList<Song> songsArrayList;
private SongBank(Context context)
{
// You can do any stuff if you want here
}
// create getter and setter methods for your arrayList
public void setSongsList(ArrayList<Song> songs)
{
if(songs!=null)
{
this.songsArrayList=songs;
}
}
public ArrayList<Song> getSongsList()
{
return this.songsArrayList;
}
public static SongBank getInstance(Context context)
{
if(instance==null)
{
instance=new SongBank(context);
}
return instance;
}
}
The instance of this singleton class can be called across various activities or fragments and you can also change the Arraylist value across different activities if you want. You can also call this class and get the list in your music service without worrying about serialization.

Losing data when sending between two classes

My app doesn't display anything when passing data from one class to another. I located through with the debugger that my ArrayList doesn't get the right value from the class.
I'm sending data with the following function:
public class Adaugare extends AppCompatActivity {
private ListView myListView;
private NumeAdapter numeAdapter;
String inume;
int ivarsta;
Intent intent = new Intent();
private ArrayList persoanaArrayList = new ArrayList<>();
public ArrayList getPersoanaArrayList() {
return persoanaArrayList;
}
public int getPersoanaArrayListsize() {
return persoanaArrayList.size();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adaugare);
myListView = (ListView) findViewById(R.id.persoana_list);
Button btn_fin = (Button) findViewById(R.id.btn_fin);
btn_fin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText nume_edit_text = (EditText) findViewById(R.id.ins_nume);
EditText varsta_edit_text = (EditText) findViewById(R.id.ins_var);
ivarsta = Integer.parseInt(varsta_edit_text.getText().toString());
inume = nume_edit_text.getText().toString();
persoanaArrayList.add(new Persoana(inume, ivarsta));
}
});
}
}
And recieving it with:
public class Afisare extends AppCompatActivity {
ListView myListView;
NumeAdapter numeAdapter;
Adaugare ad = new Adaugare();
int cate;
int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_afisare);
myListView = (ListView) findViewById(R.id.persoana_list);
ArrayList<Persoana> persoanaArrayList = new ArrayList<Persoana>(ad.getPersoanaArrayList());
numeAdapter = new NumeAdapter(this, persoanaArrayList);
myListView.setAdapter(numeAdapter);
}
The class Persoana is:
public class Persoana {
private String nume;
private int varsta;
Persoana(String inume, int ivar) {
this.nume = inume;
this.varsta = ivar;
}
public String getNume() {
return nume;
}
public int getVarsta() {
return varsta;
}
public void setNume(String nume) {
this.nume = nume;
}
public void setVarsta(int varsta) {
this.varsta = varsta;
}
}
Persoana is the main class, everything is saved in it. ad is an object of Adaugare, Adaugare being the class from which I've taken the code for getPersoanaArrayList. At debugging some values appeared at ad, namely Adaugare #4556, and persoanaArrayList remains null.
I need the persoanaArrayList so that i can initialize my Adapter and listView. Everything else in the code seems fine from step by step testing with debugger.
Your problem is with the following line in the Afisare class:
Adaugare ad = new Adaugare();
You can't simply new one activity from another activity and expect to access a shared list between them. To share instance data between java objects you need a reference to the other object. Creating a new instance will create a new empty list. That's why you are "losing" data. A quick fix would be to make the list static so it can be accessed from any instance.
But since you're dealing with Android, the right way to share data between activities is by using intent extras. The first activity starts the second activity via an intent. The first activity places the desired data in the intent as extras. The second activity uses getIntent() and the various methods on Intent to access the extras.
One last tip, in Android, you never use the new operator with Activities. Activities are created by the system to service an intent. If you find yourself using the new operator, that's a sign that you're doing something wrong.

How to get data from objected created in other class in new class - java

public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
startActivity(i);
}
}
public class ShareData {
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
public class klasaB extends Activity{
ShareData sd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int i =sd.get_numb();
System.out.println("Saved numb:" + i);
}
}
My question is, if i declare object in 1st class, and set its parameter number to 5, how to acces this number from other class because now my apk crashes when reading " int i =sd.get_numb(); " in class "klasaB".
Any suggestion how to make this work?
ps: i dont want to use static variables, or putExtra with Intents.
If data is simple/primitive then use Intent to pass data from one activity to another. That is what Intent is for.
If it is not (some sort of complex data structure or object), I would extend Application, by making a custom sub class. Application class (as the name implies) is accessible to all Activities, even when app transitions from one to another. Below is a very simple example, just to show you the idea. You can modify/adjust that to your needs.
public class MyApplication extends Application {
private X x;
public static void setX(X x) { ... }
public static X getX() { ... }
}
public class ActivityA extends Activity {
...
MyApplication.setX(x);
}
public class ActivityB extends Activity {
...
X x = MyApplication.getX();
}
You may have mixed up Activity/MainActivity/AppCombatActivity inheritance... I suspect that the reason you are seeing the error -- by the way, please look into "how to ask" and include a bit more information next time -- is that sd in klasaB is never initialized.
MainActivity.SD will hold that 5 after its onCreate(), whereas klasaB.sd is never set to anything.
You never reference or instantiate SD in class B. To get the data to ClassB you will need to set the data as an extra in the intent. Most classes cannot be sent in the intent, so for your case you should pass the primitive types of the object, then create the object.
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtra("TAG", SD.get_num());
startActivity(i);
And then in Class B
ShareData SD = new ShareData();
SD.set_num(getIntent.getIntExtra("TAG", 0);
You can access your class object either using implements Serializable or Parcelable
1.Implement serializable into your ShareData class
public class ShareData implements Serializable{
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
2.create object of SharedData and share with intent to classB
public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtras("key", SD)
startActivity(i);
}
}
3.Access in classB
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ShareData sd = (ShareData)getIntent().getSerializableExtra("key").
System.out.println("Saved numb:" + sd.get_num());
}
Use a singleton class
Declare an instance in ShareData class:
public class ShareData {
private static ShareData sdInstance = null;
...}
add this method in ShareData class:
public static ShareData getInstance(){
if(sdInstance == null){
sdInstance = new ShareData();
}
return sdInstance;
}
To get same object in other classes , use this
ShareData sd = ShareData.getInstance();
now you will receive same sd.get_numb()

how to implement a listener on an activity to update a listview adaptor

hey everyone hope you can help with this and thanks for looking at my Q.
i need to update the value of
public static int hScoreGen1 = 0; (activity A)
from another activity (activity B).
The value of hScoreGen1 is displayed in a listview in activity A
//Activity A
public void setList1(){
HashMap<String,String> temp = new HashMap<String,String>();
temp.put("catGeneral","Level 1");
temp.put("score1", String.valueOf(hScoreGen1) + "/10");
listGeneral.add(temp);
}
and
//Activity A
adapter1 = new SimpleAdapter(
this,
listGeneral,
R.layout.list_highscore_row,
new String[] {"catGeneral","score1"},
new int[] {R.id.text1,R.id.text2}
);
and
//Activity A
public static SimpleAdapter adapter1;
and this changes the value
Activity B
if (totalCorrect > ScoreScreen.currentScoreCatValue){
HighScores.hScoreGen1 = totalCorrect;
HighScores.adapter1.notifyDataSetChanged();
}
i was told making the adapter static could cause leaks. instead for listener just create an interface, implement this over the Activity where i want to update the score. Set this listener object in the base activity [apply the null check] and set the listener from second activity. which sounds right but carnt find code example of this....if your have any ideas they would be greatly appreciated.
A possible solution would be to use a Singleton class in which you store your int hScoreGen1 :
public class Singleton {
private static Singleton instance;
public static int hScoreGen1 = 0;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
public void setScore(int score) {
this.hScoreGen1 = score;
}
public int getScore(int score) {
return this.hScoreGen1;
}
}
This way, your variable hScoreGen will be initialized only once, and you'll be able to set its value in Activity A and display it in Activity B :
public class ActivityA extends Activity {
#Override
public void onCreate(...) {
Singleton score = Singleton.getInstance();
score.setScore(10);
...
}
}
public class ActivityB extends Activity {
#Override
public void onCreate(...) {
Singleton score = Singleton.getInstance();
TextView textView = (TextView) findViewById(R.id.text_view);
textView.setText(score.getScore());
...
}
}

Struggling to writing my object to Parcelable

I am trying to send an object from one activity to another, so hence I am using parcelable, and while I have created code to send it and receive it,(the code for this is at the bottom) it seems that I need some code to be able to actually write the object to the parcel.
Error While Passing An Object From An Activity To Another (Using Parcelable)
I believe what I need to do is similar to the answer given in this, so I need a writeToParcel method, which I have done in the code below. (Although at dest.writeValue(this); is where I get an error) says StackOverFlowError
I believe i may also need public static final Parcelable.Creator... although don't completely know how to write it (I have tried to write one roughly and its the bit in comments)
Also I don't know if I need a bit that would be like public Clubs (Parcel source)...
Any help would be greatly appreciated. Thanks
public class Clubs implements Parcelable{
public void setEvent(String eventType, String date) {
this.eventType = eventType;
this.date = date;
}
//contains lots of defined variables and various methods that
//aren't relevant for my question and would take up lots of room
//all like the one above.
//public static final Parcelable.Creator CREATOR
//= new Parcelable.Creator() {
// public Parcel createFromParcel(Parcel in) {
// return (in);
// }
//};
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(this);
}
}
My onItemClick class that puts the object into the parcel, and starts the new activity
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Clubs mymeeting = db.get(map.get(position));
Intent i = new Intent();
Bundle b = new Bundle();
b.putParcelable("mymeeting", mymeeting);
i.putExtras(b);
i.setClass(ListSample.this, DynamicEvents.class);
startActivity(i);
}
The start of my new activity code that will be edit later once it send the object across correctly
public class DynamicEvents extends Activity
{
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Bundle b = getIntent().getExtras();
// Create the text view
TextView textView = new TextView(this);
textView.setTextSize(20);
textView.setText(" " + b.getParcelable("mymeeting").toString());
// Set the text view as the activity layout
setContentView(textView);
}
}
Rewrite writeToParcel method as
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(eventType);
dest.writeString(date);
}
You may not be allowed to write Custom Java Object directly. Either write standard data values individually or make your object serializable and use method writeSerializable on Parcel object.

Categories