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