I'm trying to build a simple android that should simulate learning vocabulary with cards. to get to the final app, I'm going to add functionality and complexity step by step, by learning new things, and adding new things.
I'm about to tell you where I'm stuck, but first, here's what my App should do, so far (I'm still far, far way from where I'd like it to go, but you don't have to mind about that.):
At this point the app should do the folowing thing:
a) Create an Array of 3 instances of an implementation of the Parcelable interface (class VocCard implements Parcelable), VocCard[] voc1, in this case. Since the class VocCard implements Parcelable, a Parcel is obtained for the construction of the 3 instances.
I'm currently stuck at 2) c), insofar that the App only works as described above for the index 0. Only VocCard card0 = vocCardList1.get(0); works, vocCardList1.get(1), or vocCardList1.get(2); don't, despite 1 and 2 being within the ArrayList boundries.
Oddly enough, the Runtime Exeption Message for using index 1 and index 2 is not the same:
with vocCardList1.get(1): java.lang.ClassCastException: java.lang.String cannot be cast to com.undiclosed.smartcards.VocCard
with vocCardList1.get(2): java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.undisclosed.smartcards.VocCard.returnVocForeign()' on a null object reference
Why can't I acces the elements of the ArrayList the way I expected? When I searched the web I was probably looking for the wrong stuff.
MainActivity.java:
package com.undisclosed123.smartcards;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<VocCard> vocCardList;
private String[] voc_f = {"bread","apple","water"};
private String[] voc_n = {"pain","pomme","eau"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Create VocCards and add to List
vocCardList = new ArrayList<VocCard>();
VocCard[] voc1 = new VocCard[3];
Parcel in = Parcel.obtain();
for(int i = 0; i < 3; i++){
voc1[i] = new VocCard(in);
voc1[i].setVocForeign(voc_f[i]);
voc1[i].setVocNative(voc_n[i]);
vocCardList.add(voc1[i]);
}
// Create Intent and assign the parcelable List for sending to second activity on btn click
Button startBtn = (Button) findViewById(R.id.button);
startBtn.setOnClickListener(new View.OnClickListener() {
@Override
@SuppressWarnings("unchecked")
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, PracticeActivity.class);
intent.putParcelableArrayListExtra("voc1",(ArrayList)vocCardList);
getApplicationContext().startActivity(intent);
}
});
}
}
And below, PracticeActivity.java:
(Sorry for the large sections which are commented out, I figured it could help communicating my further intentions for that class)
package com.undisclosed123.smartcards;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.ArrayList;
public class PracticeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_practice);
// Get the Intent that started this activity and extract the string
Intent intent = getIntent();
final ArrayList<VocCard> vocCardList1 = intent.getParcelableArrayListExtra("voc1"); //
//Get the Data from the VocCards
//VocCard card4count = vocCardList1.get(2);
// card4count.increaseCount();
//int count = card4count.getCount();
/* if(count >= vocCardList1.size()){
// TODO
//Create new intent for EndPracticeActivity
//makeshift statement
count--;
}*/
VocCard card0 = vocCardList1.get(2);
// VocCard card1 = vocCardList1.get(1);
String test1 = card0.returnVocForeign();
// card0.increaseCount();
// String test1 = "test1";
//Make a TextView display the transfered String
TextView textView = findViewById(R.id.textView);
textView.setText(test1);
//Create another intent that recalls same activity recursively
Button nextBtn = (Button) findViewById(R.id.button2);
nextBtn.setOnClickListener(new View.OnClickListener() {
@Override
@SuppressWarnings("unchecked")
public void onClick(View v) {
Intent intent = new Intent(PracticeActivity.this, PracticeActivity.class);
intent.putParcelableArrayListExtra("voc1",(ArrayList)vocCardList1);
getApplicationContext().startActivity(intent);
}
}); /**/
}
}
And at last, VocCard.java:
package com.undisclosed123.smartcards;
import android.os.Parcel;
import android.os.Parcelable;
public class VocCard implements Parcelable {
private String voc_foreign;
private String voc_native;
private boolean learned;
private int error_level;
private static int counter;
public String returnVocForeign(){
return voc_foreign;
}
public void setVocForeign(String voc_f){
voc_foreign = voc_f;
}
public String returnVocNative(){
return voc_native;
}
public void setVocNative(String voc_n){
voc_native = voc_n;
}
public boolean checkLearned(){
return learned;
}
public int getErrorLevel(){
return error_level;
}
public void makeLearned(){
learned = true;
}
public void increaseErrorLevel(){
error_level++;
}
public int getCount(){
return counter;
}
public void increaseCount(){
counter++;
}
public VocCard(Parcel in) {
voc_foreign = in.readString();
voc_native = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(voc_foreign);
dest.writeString(voc_native);
dest.writeInt((Boolean) learned ? 1 : 0);
dest.writeInt(error_level);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<VocCard> CREATOR = new Creator<VocCard>() {
@Override
public VocCard createFromParcel(Parcel in) {
return new VocCard(in);
}
@Override
public VocCard[] newArray(int size) {
return new VocCard[size];
}
};
}
The problem is with writing data to Parcel
and reading data from it.
public class VocCard implements Parcelable {
...
...
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(voc_foreign);
dest.writeString(voc_native);
dest.writeInt(learned ? 1 : 0);
dest.writeInt(error_level);
}
/**
* This constructor is invoked by the method
* createFromParcel(Parcel source) of the object CREATOR.
*
* The order and number of writing and reading data to and from
* Parcel should be same
**/
private VocCard(Parcel in) {
voc_foreign = in.readString();
voc_native = in.readString();
learned = in.readInt() == 1;
error_level = in.readInt();
}
/**
* A constructor that initializes the VocCard object.
**/
VocCard(String voc_foreign, String voc_native) {
this.voc_foreign = voc_foreign;
this.voc_native = voc_native;
}
...
...
}
Few changes in MainActivity
inside onCreate
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
...
//Create VocCards and add to List
mVocCardList = new ArrayList<>(3);
for (int i = 0; i < 3; i++) {
mVocCardList.add(new VocCard(voc_f[i], voc_n[i]));
}
Button startBtn = (Button) findViewById(R.id.button);
startBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, PracticeActivity.class);
intent.putParcelableArrayListExtra("voc1", (ArrayList<? extends Parcelable>) mVocCardList);
startActivity(intent);
}
});
}
Now get the VocCard
list in PracticeActivity
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
...
final ArrayList<VocCard> vocCardList = getIntent().getParcelableArrayListExtra("voc1");
final VocCard card = vocCardList.get(2);
String test = card.getVocForeign();
...
...
}