1

I´ve got a little saveInstanceState problem.

One activity sends via intent a string value to another activity, which works fantastic. Now at the second activity I select one row item to get to a third activity, which works also. But if I use the actionbar BACK button (to the second activity) I get a NullPointerException.

The reason is - of course - the intent string from the first activity can´t be loaded. So at the second activity I tried saving this intent string value as instance state and get this value at oncreate methode again. I´ve googlet a lot, I´ve tried a lot. But the Nullpointer won´t disappear.

Would be great to have a little hint.

My Code of the second activity:

    package de.cityknight.app;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


public class RouteChooseActivity extends ActionBarActivity implements OnItemClickListener {

    String citySave;
    String[] titelRoute;
    String[] descRoute;
    Integer[] bildRoute;

    ListView listView;
    List<RowItem> rowItems;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_route_choose);
        Bundle b = getIntent().getExtras();
        if (savedInstanceState != null) {
                savedInstanceState.getString("stadt");
         }
         else {
            b.getString("stadt");
         }
            TextView headingRoute = (TextView) findViewById(R.id.routeTitel);
            headingRoute.setText(String.format(getResources().getString(R.string.route_text)) + " " + b.getString("stadt") + " aus:");
            if (b.getString("stadt").equals("Passau")) {
                titelRoute = new String[]{"Die Altstadt", "Universität", "Essen und Trinken"};
                descRoute = new String[]{"Die Altstadt Passaus bietet viele Attraktion: Rathaus, Dom und die vielen kleinen Gassen.",
                        "Deutschlands schönster Campus.", "Kulinarische Köstlichkeiten in Passau"};
                bildRoute = new Integer[]{R.drawable.augsburg, R.drawable.bamberg, R.drawable.passau};
            } else if (b.getString("stadt").equals("Augsburg")) {
                titelRoute = new String[]{"Augsburg1", "Augsburg2", "Augsburg3"};
                descRoute = new String[]{"Bla bla", "Mehr Bla", "Blubb"};
                bildRoute = new Integer[]{R.drawable.augsburg, R.drawable.bamberg, R.drawable.passau};
            } else if (b.getString("stadt").equals("Bamberg")) {
                titelRoute = new String[]{"Bamberg", "Bamberg2", "Bamberg3"};
                descRoute = new String[]{"Bla bla", "Mehr Bla", "Blubb"};
                bildRoute = new Integer[]{R.drawable.augsburg, R.drawable.bamberg, R.drawable.passau};
            } else {
                try {
                    TextView errorMessage = (TextView) findViewById(R.id.routeTitel);
                    errorMessage.setText(R.string.errorroute);
                } catch (NullPointerException e) {
                    Context context = getApplicationContext();
                    CharSequence text = getResources().getString(R.string.errorroute);
                    int duration = Toast.LENGTH_LONG;
                    Toast toast = Toast.makeText(context, text, duration);
                    toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
                    toast.show();
                }

            }

            try {
                rowItems = new ArrayList<RowItem>();
                for (int i = 0; i < titelRoute.length; i++) {
                    RowItem item = new RowItem(bildRoute[i], titelRoute[i], descRoute[i]);
                    rowItems.add(item);
                }
                Comparator<RowItem> sortRoutes = new Comparator<RowItem>() {
                    @Override
                    public int compare(RowItem rowItem1, RowItem rowItem2) {
                        return rowItem1.getTitle().compareTo(rowItem2.getTitle());
                    }
                };
                Collections.sort(rowItems, sortRoutes);
                listView = (ListView) findViewById(R.id.listRoute);
                CityListViewAdapter adapter = new CityListViewAdapter(this, R.layout.row_items, rowItems);
                listView.setAdapter(adapter);
                listView.setOnItemClickListener(this);
            } catch (ArrayIndexOutOfBoundsException rowItems) {
                Context context = getApplicationContext();
                CharSequence text = getResources().getString(R.string.ressourcefailed);
                int duration = Toast.LENGTH_LONG;
                Toast toast = Toast.makeText(context, text, duration);
                toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
                toast.show();
            }

    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Intent intent = new Intent();
        intent.setClass(RouteChooseActivity.this, RouteView.class);
        RowItem item = (RowItem) parent.getItemAtPosition(position);
        Bundle b = new Bundle();
        b.putString("route", item.getTitle().toString());
        intent.putExtras(b);
        startActivity(intent);
    }

    protected void onSaveInstanceState(Bundle savedInstanceState) {
        Bundle b = getIntent().getExtras();
        b.getString("stadt");
        savedInstanceState.putString("stadt", citySave);
        super.onSaveInstanceState(savedInstanceState);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        // Restore UI state from the savedInstanceState.
        // This bundle has also been passed to onCreate.
        savedInstanceState.getString(citySave);
        Log.i("debug", "saved data: " + citySave);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.route, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        switch (item.getItemId()) {
            case R.id.action_stadt:
                setContentView(R.layout.activity_stadt);
                Intent stadt = new Intent(RouteChooseActivity.this, StadtActivity.class);
                startActivity(stadt);
                return true;
            case R.id.action_help:
                setContentView(R.layout.activity_help);
                Intent help = new Intent(RouteChooseActivity.this, Help.class);
                startActivity(help);
                return true;
            case R.id.action_exit:
                moveTaskToBack(true);
                System.exit(0);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
    }
ben
  • 161
  • 3
  • 18

3 Answers3

2
  1. That will raise a NullPointerException :

    savedInstanceState.getString(citySave);
    Log.i("debug", "saved data: " + citySave);
    

    It should be :

    citySave = savedInstanceState.getString("stadt");
    Log.i("debug", "saved data: " + citySave);
    
  2. In onSaveInstanceState you should call super.onSaveInstanceState(savedInstanceState); before adding strings to savedInstanceState (or it will be wiped out ...)

  3. The whole savedInstanceState is not really suited for that purpose. Android can delete it when you go to your 3th activity ! (it depends if the system thinks that it needs memory and thus completly destroys the 2th activity and its savedInstanceState with it).

    The good way of doing things is to override the onBackPressed() method of your 3th activity to fire an intent to launch your 2th activity with the value put in the "Extra" bundle of the Intent.

    With this approach your issue should be resolved.

poulpi
  • 101
  • 7
1

You have two errors as I can see:

Firstly, you haven't actually used the savedInstanceState. Yes you are calling the function, but nowhere are you actually using the value it returns.

String myNewString;
Bundle b = getIntent().getExtras();
if (savedInstanceState != null) {
    myNewString = savedInstanceState.getString("stadt");
} else {
    myNewString = b.getString("stadt");
}

Now use myNewString instead of b.getString("stadt").

Secondly,try putting the code into the onResume function. the onCreate() function will not run if you are pressing the back button to return to the second activity.

Saket Jain
  • 1,352
  • 2
  • 12
  • 25
0

I´ve figured it out.

You need three things for getting a good lifecycle - savedInstanceState if your activity is destroyed, - onResume, if your activity is paused by another app or activity screen, for example if you select a rowItem, which starts a new activity.

For my problem the following did it: Second activity:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_route_choose);
        Bundle b = getIntent().getExtras();
        citySave = b.getString("stadt");

@Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Intent intent = new Intent();
        intent.setClass(RouteChooseActivity.this, RouteView.class);
        RowItem item = (RowItem) parent.getItemAtPosition(position);
        Bundle b = new Bundle();
        b.putString("route", item.getTitle().toString());
        b.putString("stadt", citySave);
        intent.putExtras(b);
        startActivity(intent);
    }

    protected void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        Bundle b = getIntent().getExtras();
        citySave = b.getString("stadt");
        savedInstanceState.putString("stadt", citySave);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        // Restore UI state from the savedInstanceState.
        // This bundle has also been passed to onCreate.
        citySave = savedInstanceState.getString("stadt");
        Log.i("debug", "saved data: " + citySave);
    }

    public void onResume() {
        super.onResume();

            Bundle b = getIntent().getExtras();
            citySave = b.getString("stadt");

    }

Third activity:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_route_view);
        Bundle b = getIntent().getExtras();
        b.getString("route");
        citySave = b.getString("stadt");

    public void onBackPressed() {
        super.onBackPressed();
        Intent intent = new Intent();
        intent.setClass(RouteView.this, RouteChooseActivity.class);
        Bundle b = new Bundle();
        b.putString("stadt", citySave);
        intent.putExtras(b);
        startActivity(intent);
        finish();
    }

    public void onPause() {
        super.onPause();
        Intent intent = new Intent();
        intent.setClass(RouteView.this, RouteChooseActivity.class);
        Bundle b = new Bundle();
        b.putString("stadt", citySave);
        intent.putExtras(b);
        startActivity(intent);
        finish();
    }
ben
  • 161
  • 3
  • 18