0

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:

  • 1) in the MainActivity:

  • 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.

  • b) Create an ArrayList of the type VocCard called vocCardList and add all 3 elements of voc1 to vocCardList.
  • c) Create an instance of a start button which creates an intent for starting a 2nd activity called PracticeActivity when clicked.
  • d) Add the ArrayList vocCardList with Parcelable to the intent.

2) in PracticeActivity

  • a) Get the intent created by MainActivity.
  • b) Retrieve ArrayList vocCardList from intent
  • c) Get any element of vocCardsList and assign a variable of the type VocCard to it.
  • d) Retrieve a value of the assigned Voccard instance by invoking its methods.
  • e) Display that value by setting a TextView to the value's String value.
  • f) Create a Button nextButton which creates an intent for starting the 2nd activity PracticeActivity again, as some kind of recursion.
  • g) Add the ArrayList vocCardList with parcelable to intent.
  • h) repeat 2) a)-g) until App is closed by closing-icon.

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

Question:

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];
        }
    };
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Schelmuffsky
  • 320
  • 1
  • 13
  • 3
    Welcome to Stack Overflow. I suggest you take a moment to read [ask] and [mcve] for tips on asking a good question that will more likely attract the answers you want. In particular, describe what happens when you run your code. Does it compile? If not, what error do you get and what line causes the error? If it runs, do you get any runtime errors? If so what are they? These are all details that will help us show you how to solve the problem yourself next time. – Code-Apprentice May 08 '18 at 18:59
  • Thanks for your good intentions! Although, unless this is a default message, i'd like to add that your comment is a bit frustrating, considering that i spent quite some time figuring out how to elaborate my problem as detailed and clear as possible. "Does it compile? If not, what error do you get and what line causes the error? If it runs, do you get any runtime errors? If so what are they?" - That's all mentioned in my post. So, what's missing? – Schelmuffsky May 08 '18 at 19:16
  • Even though I could save time by copy-pasting default messages, I don't do this. I write custom messages for all SO posters to ask for additional information when I think it is needed for me or another user to write an answer. It will help tremendously if you post the entire stacktrace of your error message, not just the first line. You can also use formatting similar to your code formatting (4 spaces before each line). – Code-Apprentice May 08 '18 at 19:19
  • I see. I'll edit it .Thanks again! – Schelmuffsky May 08 '18 at 19:26
  • 1
    (Aside: I have trimmed some remarks about how this is _definitely_ not a duplicate, and that you have _really_ searched the web etc - note that everyone says this, and the effect it has on readers is a pleading and insistent tone that invites downvotes. I recommend refraining from this sort of thing in questions - stick to code and succinct description if you can, and [ask confident questions](https://meta.stackoverflow.com/q/366264/472495)). – halfer May 08 '18 at 22:40
  • Thanks for cleaning up! Do you think, I should still edit-in the RTError Codes? – Schelmuffsky May 09 '18 at 04:48

1 Answers1

0

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();

    ... 
    ...

}
halfer
  • 19,824
  • 17
  • 99
  • 186
Hussain
  • 1,243
  • 12
  • 21
  • Thank you very much! I followed your instructions as closely as possible, and the RuntimeError don't appear anymore. (Actually, I got the code running without RT errors by by only changing some variable names, before, but i can only speculate about why it worked, but I'd rather not. I like your implementation suggestions.) – Schelmuffsky May 09 '18 at 01:47