samedi 27 juin 2015

App crashes on orientation change after I change my listview in same activity

My app starts in the MainActivity and uses a loader and custom adapter to populate my listview with the users' favourites. The data will persist over the orientation change.

But then if the user performs a search the listview in the MainActivity is repopulated with the new data. That works fine. But now, an orientation change crashes my app.

I'm also confused whether I have to explicitly save my instance before an orientation change or if Android does it for me. And if I have to do it explicitly would it be better to just perform the database query again instead?

package must.beunique.recipebook;

import java.io.File;

import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.CursorAdapter;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.ListView;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.widget.AdapterView.OnItemClickListener;
import android.view.View;
import android.widget.SearchView;
import android.util.Log;

public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> {

    private CursorAdapter dataAdapter;
    private String query = null;

    private static final String DATABASE_PATH = "/data/data/must.beunique.recipebook/databases/RECIPES";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.w("DEBUG", "MainActivity - onCreate()");
        super.onCreate(savedInstanceState);

        setContentView(R.layout.query_results);     



            File database = this.getDatabasePath(DATABASE_PATH);
            if (database.exists()) {    


                // Get the intent, verify the action and get the query
                Intent intent = getIntent();
                Bundle extras = intent.getExtras();

                // search query in intent
                if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
                    query = intent.getStringExtra(SearchManager.QUERY);
                }         
                // browse all...
                else if(extras!=null){
                    if(extras.containsKey("browse")){
                        query = "";
                    }
                }                                           

                Log.w("DEBUG", "starting adapter");
                int[] to = new int[] { R.id.text1 };
                String[] columns = new String[]{ "name" };
                dataAdapter = new CustomAdapter(this, R.layout.text_view, null, columns, to, Adapter.NO_SELECTION);
                ListView listView = (ListView) findViewById(android.R.id.list);
                listView.setAdapter(dataAdapter);

                Log.w("DEBUG", "listView.setAdapter(dataAdapter)");
                listView.setOnItemClickListener(new OnItemClickListener()
                {

                    @Override
                    public void onItemClick(AdapterView<?> arg0, View view,
                            int position, long id) {
                        Intent intent = new Intent(getBaseContext(), Recipe.class);
                        intent.putExtra("must.beunique.recipebook._id", (int)id);
                        startActivity(intent);
                    }   
                }       );
                Log.w("DEBUG", "end adapter");
                getSupportLoaderManager().initLoader(0, null, this);

            }
            else{
                new SyncRecipes(this).execute(); 
            } 

        Log.w("DEBUG", "end onCreate()");
    }

    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        Log.w("DEBUG", "onCreateLoader()");
        if(query==""){
            // empty search, return all
            return new CursorLoader(this, Uri.parse("content://must.beunique.recipebook.data/"+DataProvider.BRW), null, null, null, null);          
        }
        else if(query == null){
            return new CursorLoader(this, Uri.parse("content://must.beunique.recipebook.data/"+DataProvider.FAV), null, null, null, null);
        }
        else{
            // term search, return relevant
            return new CursorLoader(this, Uri.parse("content://must.beunique.recipebook.data/"+DataProvider.TRM+"/"+query), null, null, null, null);
        }
    }

    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        Log.w("DEBUG", "onLoadFinished()");
        dataAdapter.swapCursor(cursor);
    }

    public void onLoaderReset(Loader<Cursor> cursorLoader) {
        dataAdapter.swapCursor(null);
    }

    protected void onDestroy(Bundle savedInstanceState) {
        super.onDestroy();
    }

    @Override
    public void onSaveInstanceState(Bundle InstanceState) {
        super.onSaveInstanceState(InstanceState);
        InstanceState.putString("query", query);
        dataAdapter.swapCursor(null);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu, menu);
         // Associate searchable configuration with the SearchView
        SearchManager searchManager =
               (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
                (SearchView) menu.findItem(R.id.search).getActionView();
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));
        Log.w("DEBUG", "end - onCreateOptionsMenu()");
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu){
        Log.w("DEBUG", "onPrepareOptionsMenu()");
            menu.findItem(R.id.favourite).setVisible(false);
            menu.findItem(R.id.favourite).setEnabled(false);
            menu.findItem(android.R.id.home).setVisible(true);
            menu.findItem(android.R.id.home).setEnabled(true);
        Log.w("DEBUG", "end - onPrepareOptionsMenu()");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
            case android.R.id.home:            
                Intent intent = new Intent(this, MainActivity.class);
                startActivity(intent);            
                return true; 
            case R.id.search:
                onSearchRequested();
                return true;
            case R.id.browse:
                Intent bintent = new Intent(this, MainActivity.class);
                bintent.putExtra("browse", true);
                startActivity(bintent);;
                return true;            
            case R.id.sync:
                new SyncRecipes(this).execute();
                return true;
            case R.id.rebuild:
                Boolean Qdeleted = this.deleteDatabase(DATABASE_PATH);
                new SyncRecipes(this).execute();
                return true;                                
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

I can't interpret the logcat

06-27 22:15:52.421: W/DEBUG(29310): MainActivity - onCreate()
06-27 22:15:52.531: D/AbsListView(29310): Get MotionRecognitionManager
06-27 22:15:52.551: W/DEBUG(29310): starting adapter
06-27 22:15:52.556: W/DEBUG(29310): listView.setAdapter(dataAdapter)
06-27 22:15:52.556: W/DEBUG(29310): end adapter
06-27 22:15:52.561: W/DEBUG(29310): onCreateLoader()
06-27 22:15:52.566: W/DEBUG(29310): end onCreate()
06-27 22:15:52.691: D/libEGL(29310): loaded /system/lib/egl/libEGL_mali.so
06-27 22:15:52.696: D/libEGL(29310): loaded /system/lib/egl/libGLESv1_CM_mali.so
06-27 22:15:52.701: D/libEGL(29310): loaded /system/lib/egl/libGLESv2_mali.so
06-27 22:15:52.706: E/(29310): Device driver API match
06-27 22:15:52.706: E/(29310): Device driver API version: 23
06-27 22:15:52.706: E/(29310): User space API version: 23 
06-27 22:15:52.706: E/(29310): mali: REVISION=Linux-r3p2-01rel3 BUILD_DATE=Fri Mar 21 13:52:50 KST 2014 
06-27 22:15:52.771: D/OpenGLRenderer(29310): Enabling debug mode 0
06-27 22:15:52.781: W/DEBUG(29310): onCreateOptionsMenu()
06-27 22:15:52.816: W/DEBUG(29310): end - onCreateOptionsMenu()
06-27 22:15:52.816: W/DEBUG(29310): onPrepareOptionsMenu()
06-27 22:15:52.816: W/DEBUG(29310): end - onPrepareOptionsMenu()
06-27 22:15:52.856: W/DEBUG(29310): onLoadFinished()
06-27 22:15:52.856: W/DEBUG(29310): end - onLoadFinished()
06-27 22:15:56.846: D/AbsListView(29310): Get MotionRecognitionManager
06-27 22:15:58.281: D/AbsListView(29310): onDetachedFromWindow
06-27 22:15:58.291: W/DEBUG(29310): MainActivity - onCreate()
06-27 22:15:58.346: D/AbsListView(29310): Get MotionRecognitionManager
06-27 22:15:58.351: W/DEBUG(29310): starting adapter
06-27 22:15:58.351: W/DEBUG(29310): listView.setAdapter(dataAdapter)
06-27 22:15:58.351: W/DEBUG(29310): end adapter
06-27 22:15:58.351: W/DEBUG(29310): onCreateLoader()
06-27 22:15:58.351: W/DEBUG(29310): end onCreate()
06-27 22:15:58.486: W/DEBUG(29310): onCreateOptionsMenu()
06-27 22:15:58.516: W/DEBUG(29310): end - onCreateOptionsMenu()
06-27 22:15:58.516: W/DEBUG(29310): onPrepareOptionsMenu()
06-27 22:15:58.516: W/DEBUG(29310): end - onPrepareOptionsMenu()
06-27 22:15:58.746: W/DEBUG(29310): onLoadFinished()
06-27 22:15:58.746: W/DEBUG(29310): end - onLoadFinished()
06-27 22:15:58.981: W/DEBUG(29310): onSaveInstanceState()
06-27 22:16:00.846: W/DEBUG(29310): onSaveInstanceState()
06-27 22:16:00.856: D/AbsListView(29310): onDetachedFromWindow
06-27 22:16:01.101: W/DEBUG(29310): MainActivity - onCreate()
06-27 22:16:01.166: D/AbsListView(29310): Get MotionRecognitionManager
06-27 22:16:01.171: W/DEBUG(29310): starting adapter
06-27 22:16:01.171: W/DEBUG(29310): listView.setAdapter(dataAdapter)
06-27 22:16:01.171: W/DEBUG(29310): end adapter
06-27 22:16:01.171: W/DEBUG(29310): end onCreate()
06-27 22:16:01.171: W/DEBUG(29310): onLoadFinished()
06-27 22:16:01.171: W/DEBUG(29310): end - onLoadFinished()
06-27 22:16:01.221: D/AndroidRuntime(29310): Shutting down VM
06-27 22:16:01.221: W/dalvikvm(29310): threadid=1: thread exiting with uncaught exception (group=0x418b4c08)
06-27 22:16:01.231: E/AndroidRuntime(29310): FATAL EXCEPTION: main
06-27 22:16:01.231: E/AndroidRuntime(29310): Process: must.beunique.recipebook, PID: 29310
06-27 22:16:01.231: E/AndroidRuntime(29310): android.view.InflateException: Binary XML file line #31: Error inflating class <unknown>
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.LayoutInflater.createView(LayoutInflater.java:626)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:675)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:700)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at com.android.internal.widget.ActionBarContextView.initClose(ActionBarContextView.java:330)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at com.android.internal.widget.ActionBarContextView.onConfigurationChanged(ActionBarContextView.java:185)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.View.dispatchConfigurationChanged(View.java:8599)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.ViewGroup.dispatchConfigurationChanged(ViewGroup.java:1105)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.ViewGroup.dispatchConfigurationChanged(ViewGroup.java:1110)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.ViewGroup.dispatchConfigurationChanged(ViewGroup.java:1110)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.ViewGroup.dispatchConfigurationChanged(ViewGroup.java:1110)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.ViewRootImpl.updateConfiguration(ViewRootImpl.java:3441)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3612)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.os.Handler.dispatchMessage(Handler.java:102)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.os.Looper.loop(Looper.java:146)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.app.ActivityThread.main(ActivityThread.java:5593)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at java.lang.reflect.Method.invokeNative(Native Method)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at java.lang.reflect.Method.invoke(Method.java:515)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at dalvik.system.NativeStart.main(Native Method)
06-27 22:16:01.231: E/AndroidRuntime(29310): Caused by: java.lang.reflect.InvocationTargetException
06-27 22:16:01.231: E/AndroidRuntime(29310):    at java.lang.reflect.Constructor.constructNative(Native Method)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.view.LayoutInflater.createView(LayoutInflater.java:600)
06-27 22:16:01.231: E/AndroidRuntime(29310):    ... 23 more
06-27 22:16:01.231: E/AndroidRuntime(29310): Caused by: java.lang.ArrayIndexOutOfBoundsException: length=24; index=27
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.content.res.StringBlock.get(StringBlock.java:65)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.content.res.XmlBlock$Parser.getPooledString(XmlBlock.java:459)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.content.res.TypedArray.loadStringValueAt(TypedArray.java:721)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.content.res.TypedArray.getString(TypedArray.java:125)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.widget.TextView.<init>(TextView.java:1509)
06-27 22:16:01.231: E/AndroidRuntime(29310):    at android.widget.TextView.<init>(TextView.java:908)
06-27 22:16:01.231: E/AndroidRuntime(29310):    ... 26 more

LAYOUT XML's

query_results.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://ift.tt/nIICcg"
    style = "@style/Activity"
>   
    <ListView 
        android:id="@android:id/list"
        style = "@style/ListView"       
    />          

</LinearLayout>

text_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://ift.tt/nIICcg"
    android:orientation="vertical"
>       

    <TextView 
         style = "@style/Item"
         android:id="@+id/text1"
         android:hint="@string/no_recipes" 
         android:maxLines="1"    /> 

</LinearLayout>

Aucun commentaire:

Enregistrer un commentaire