Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Hariidaran Tamilmaran
seal-mask
.a{fill-rule:evenodd;}techdegree
Hariidaran Tamilmaran
iOS Development Techdegree Student 19,305 Points

Help on the Story and StoryActivity classes!

In a video, Ben hard-codes all the data in the Story class. I thought of typing that in the strings.xml file so the MVC pattern would make sense. But unfortunately, when I was running the app, it crashed after I pressed the Start Your Adventure button. Here is the code:

MainActivity.java
package com.hariidaran.signalsfrommars.ui;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.hariidaran.signalsfrommars.R;

public class MainActivity extends Activity {

    private EditText mNameField;
    private Button mStartButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mNameField = (EditText) findViewById(R.id.nameField);
        mStartButton = (Button) findViewById(R.id.startButton);

        mStartButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = mNameField.getText().toString();
                // starts StoryActivity
                Intent intent = new Intent(MainActivity.this, StoryActivity.class);
                intent.putExtra(getString(R.string.key_name), name);
                startActivity(intent);
            }
        });
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.MainActivity"
    android:background="#FFFFFFFF">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/mainTitleImage"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:src="@drawable/main_title"
        android:scaleType="fitXY"
        android:layout_alignParentEnd="true"
        android:adjustViewBounds="true"
        android:contentDescription="Main Title Image"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="START YOUR ADVENTURE"
        android:id="@+id/startButton"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:textColor="#FF3A8AEC"
        android:background="#FFFFFFFF"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textPersonName"
        android:ems="10"
        android:id="@+id/nameField"
        android:hint="Enter your name to begin"
        android:maxLength="30"
        android:layout_above="@+id/startButton"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"/>
</RelativeLayout>
StoryActivity.java
package com.hariidaran.signalsfrommars.ui;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.hariidaran.signalsfrommars.R;
import com.hariidaran.signalsfrommars.model.Page;
import com.hariidaran.signalsfrommars.model.Story;

public class StoryActivity extends Activity {

    private String mName;
    private Story mStory;
    private ImageView mStoryImage;
    private TextView mText;
    private Button mChoice1;
    private Button mChoice2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_story);

        Intent intent = getIntent();
        mName = intent.getStringExtra(getString(R.string.key_name));

        if (mName == null) {
            mName = "Friend";
        }

        mStory = new Story();
        mStoryImage = (ImageView) findViewById(R.id.storyImage);
        mText = (TextView) findViewById(R.id.text);
        mChoice1 = (Button) findViewById(R.id.choice1);
        mChoice2 = (Button) findViewById(R.id.choice2);

        loadPage();
    }

    private void loadPage() {
        Page page = mStory.getPage(0);

        mStoryImage.setImageDrawable(page.getImage());

        String pageText = page.getText();
        pageText = String.format(pageText, mName);

        mText.setText(pageText);

        mChoice1.setText(page.getChoice1().getText());

        mChoice2.setText(page.getChoice2().getText());
    }
}
activity_story.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.StoryActivity"
    android:background="#ffffff">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/storyImage"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:src="@drawable/page0"
        android:scaleType="fitXY"
        android:adjustViewBounds="true"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="On your return trip from studying Saturn&apos;s rings, you hear a distress signal that seems to be coming from the surface of Mars. It&apos;s strange because there hasn&apos;t been a colony there in years. Even stranger, it&apos;s calling you by name: &quot;Help me, %1$s, you&apos;re my only hope.&quot;"
        android:id="@+id/text"
        android:layout_below="@+id/storyImage"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:paddingTop="30dp"
        android:paddingLeft="30dp"
        android:paddingRight="30dp"
        android:lineSpacingMultiplier="1.2"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/choice2"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:background="#ffffff"
        android:theme="@style/Widget.AppCompat.Button.Borderless.Colored"
        android:textColor="#3a8aec"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/choice1"
        android:layout_above="@+id/choice2"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:background="#ffffff"
        android:theme="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
        style="?android:attr/borderlessButtonStyle"
        android:textColor="#3a8aec"/>
</RelativeLayout>
Page.java
package com.hariidaran.signalsfrommars.model;

import android.graphics.drawable.Drawable;

public class Page {
    private Drawable mImage;
    private String mText;
    private Choice mChoice1;
    private Choice mChoice2;

    private Boolean mIsFinal = false;

    public Page(Drawable imageId, String text, Choice choice1, Choice choice2) {
        mImage = imageId;
        mText = text;
        mChoice1 = choice1;
        mChoice2 = choice2;
    }

    public Page(Drawable imageId, String text) {
        mImage = imageId;
        mText = text;
        mChoice1 = null;
        mChoice2 = null;
        mIsFinal = true;
    }

    public Drawable getImage() {
        return mImage;
    }

    public void setImage(Drawable imageId) {
        mImage = imageId;
    }

    public String getText() {
        return mText;
    }

    public void setText(String text) {
        mText = text;
    }

    public Choice getChoice1() {
        return mChoice1;
    }

    public void setChoice1(Choice choice1) {
        mChoice1 = choice1;
    }

    public Choice getChoice2() {
        return mChoice2;
    }

    public void setChoice2(Choice choice2) {
        mChoice2 = choice2;
    }

    public Boolean getFinal() {
        return mIsFinal;
    }

    public void setFinal(Boolean aFinal) {
        mIsFinal = aFinal;
    }
}
Choice.java
package com.hariidaran.signalsfrommars.model;

public class Choice {
    private String mText;
    private int mNextPage;

    public Choice(String text, int nextPage) {
        mText = text;
        mNextPage = nextPage;
    }

    public String getText() {
        return mText;
    }

    public void setText(String text) {
        mText = text;
    }

    public int getNextPage() {
        return mNextPage;
    }

    public void setNextPage(int nextPage) {
        mNextPage = nextPage;
    }
}
Story.java
package com.hariidaran.signalsfrommars.model;

import android.content.res.Resources;
import android.content.res.TypedArray;

import com.hariidaran.signalsfrommars.R;

public class Story {

    private Resources mResources = Resources.getSystem();
    private Page[] mPages;
    private TypedArray mImageIds = mResources.obtainTypedArray(R.array.image_ids);
    private String[] mTexts = mResources.getStringArray(R.array.text);
    private String[] mChoices1 = mResources.getStringArray(R.array.choices_1);
    private String[] mChoices2 = mResources.getStringArray(R.array.choices_2);
    private int[] mNextPages1 = mResources.getIntArray(R.array.nextPages_1);
    private int[] mNextPages2 = mResources.getIntArray(R.array.nextPages_2);

    public Story() {
        mPages = new Page[7];

        for (int i = 0; i < mPages.length; i++) {
            if (mChoices1[i].equals("(nothing)")) {
                mChoices1[i] = null;
            }

            if (mChoices2[i].equals("(nothing)")) {
                mChoices2[i] = null;
            }

            mPages[i] = new Page(
                    mImageIds.getDrawable(i),
                    mTexts[i],
                    new Choice(mChoices1[i], mNextPages1[i]),
                    new Choice(mChoices2[i], mNextPages2[i]));
        }
    }

    public Page getPage(int pageNumber) {
        return mPages[pageNumber];
    }
}
strings.xml
<resources>
    <string name="app_name">Signals from Mars</string>
    <string name="key_name">name</string>

    <array name="image_ids">
        <item>@drawable/page0</item>
        <item>@drawable/page1</item>
        <item>@drawable/page2</item>
        <item>@drawable/page3</item>
        <item>@drawable/page4</item>
        <item>@drawable/page5</item>
        <item>@drawable/page6</item>
    </array>

    <string-array name="text">
        <item>On your return trip from studying Saturn\'s rings, you hear a distress signal that
            seems to be coming from the surface of Mars. It\'s strange because there hasn\'t been
            a colony there in years. Even stranger, it\'s calling you by name: "Help me, %1$s,
            you\'re my only hope."</item>
        <item>You deftly land your ship near where the distress signal originated. You didn\'t
            notice anything strange on your fly-by, but there is a cave in front of you. Behind you is an abandoned rover from the early 21st century.</item>
        <item>You continue your course to Earth. Two days later, you receive a transmission from HQ saying that they have detected some sort of anomaly on the surface of Mars near an abandoned rover. They ask you to investigate, but ultimately the decision is yours because your mission has already run much longer than planned and supplies are low.</item>
        <item>Your EVA suit is equipped with a headlamp, which you use to navigate the cave.
            After searching for a while your oxygen levels are starting to get pretty low. You know you should go refill your tank, but there\'s a very faint light up ahead.</item>
        <item>The rover is covered in dust and most of the solar panels are broken. But you are
            quite surprised to see the on-board system booted up and running. In fact, there is a
            message on the screen: "%1$s, come to 28.543436, -81.369031." Those coordinates aren\'t far, but you don\'t know if your oxygen will last there and back.</item>
        <item>After a long walk slightly uphill, you end up at the top of a small crater. You look around, and are overjoyed to see your favorite android, %1$s-S1124. It had been lost on a previous mission to Mars! You take it back to your ship and fly back to Earth.</item>
        <item>You arrive home on Earth. While your mission was a success, you forever wonder what was sending that signal. Perhaps a future mission will be able to investigate...</item>
    </string-array>

    <string-array name="choices_1">
        <item>Stop and investigate</item>
        <item>Explore the cave</item>
        <item>Head back to Mars to investigate</item>
        <item>Refill at ship and explore the rover</item>
        <item>Explore the coordinates</item>
        <item>(nothing)</item>
        <item>(nothing)</item>
    </string-array>

    <integer-array name="nextPages_1">
        <item>1</item>
        <item>3</item>
        <item>4</item>
        <item>4</item>
        <item>5</item>
        <item>0</item>
        <item>0</item>
    </integer-array>

    <string-array name="choices_2">
        <item>Continue home to Earth</item>
        <item>Explore the rover</item>
        <item>Continue home to Earth</item>
        <item>Continue towards the faint light</item>
        <item>Return to Earth</item>
        <item>(nothing)</item>
        <item>(nothing)</item>
    </string-array>

    <integer-array name="nextPages_2">
        <item>2</item>
        <item>4</item>
        <item>6</item>
        <item>5</item>
        <item>6</item>
        <item>0</item>
        <item>0</item>
    </integer-array>
</resources>

Here are the errors which I noticed (which could possibly be related to the issue):

Caused by: android.content.res.Resources$NotFoundException: Array resource ID #0x7f0b0002
at android.content.res.Resources.obtainTypedArray(Resources.java:586)
at com.hariidaran.signalsfrommars.model.Story.<init>(Story.java:12)
at com.hariidaran.signalsfrommars.ui.StoryActivity.<init>(StoryActivity.java:19)

I checked the R class and saw that the ID #0x7f0b0002 was R.array.image_ids. Hopefully this information helps!

I need help because I won't be able to continue the course. Can explanations be given so I can understand why the specific code is wrong? Thanks for the help!

1 Answer

Seth Kroger
Seth Kroger
56,413 Points

Your app's resources aren't the same as the systems resources. If you want to access your app's resources you'll need to pass a Context to your Story constructor (since Activities are Contexts, you'll be passing this from within onCreate()) and access the resources from the Context (context.getResources())instead of using initializers.

Hariidaran Tamilmaran
seal-mask
.a{fill-rule:evenodd;}techdegree
Hariidaran Tamilmaran
iOS Development Techdegree Student 19,305 Points

Wow okay, I didn't know that. I just read up the Resources class on the Android documentation, and I thought it referred to the app's resources, because I saw the examples. And by the way, does my app adhere to MVC pattern? Thanks for clearing my doubts!