Search code examples
androidswipeandroid-sqliteandroid-listfragment

Swipe to dismiss causing inflateexception and illegalstateexception?


I'm trying to implement swipe to dismimss in my app's listfragment's list items. I'm using Jake Wharton's NineOldAndroids backport of Roman Nurik's code. However, when I add it into my fragment's onCreate(), I'm getting an inflateexception and an illegalstateexception regarding the getListView() method for the second exception. Here is my ListFragment:

package com.example.sample;

import java.util.ArrayList;

import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockListFragment;

/**
 * A list fragment representing a list of Courses. This fragment also supports
 * tablet devices by allowing list items to be given an 'activated' state upon
 * selection. This helps indicate which item is currently being viewed in a
 * {@link CourseDetailFragment}.
 * <p>
 * Activities containing this fragment MUST implement the {@link Callbacks}
 * interface.
 */
public class CourseListFragment extends SherlockListFragment {

SQLiteDatabase db;
DbHelper dbHelper;

private static String courseName;
ArrayList<String> courseItems;
ArrayAdapter<String> adapter;
/**
 * The serialization (saved instance state) Bundle key representing the
 * activated item position. Only used on tablets.
 */
private static final String STATE_ACTIVATED_POSITION = "activated_position";

/**
 * The fragment's current callback object, which is notified of list item
 * clicks.
 */
private Callbacks mCallbacks = sDummyCallbacks;

/**
 * The current activated item position. Only used on tablets.
 */
private int mActivatedPosition = ListView.INVALID_POSITION;

/**
 * A callback interface that all activities containing this fragment must
 * implement. This mechanism allows activities to be notified of item
 * selections.
 */
public interface Callbacks {
    /**
     * Callback for when an item has been selected.
     */
    public void onItemSelected(String id);
}

/**
 * A dummy implementation of the {@link Callbacks} interface that does
 * nothing. Used only when this fragment is not attached to an activity.
 */
private static Callbacks sDummyCallbacks = new Callbacks() {
    @Override
    public void onItemSelected(String id) {
    }
};

/**
 * Mandatory empty constructor for the fragment manager to instantiate the
 * fragment (e.g. upon screen orientation changes).
 */
public CourseListFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    dbHelper = new DbHelper(getActivity());
    db = dbHelper.getReadableDatabase();
    courseItems = new ArrayList<String>();
    int layout = (Build.VERSION.SDK_INT >= 11) ? android.R.layout.simple_list_item_activated_1
            : android.R.layout.simple_list_item_1;
    adapter = new ArrayAdapter<String>(getActivity(), layout, courseItems);
    // TODO: replace with a real list adapter.
    setListAdapter(adapter);
    //The problem starts here
    SwipeDismissListViewTouchListener touchListener =
            new SwipeDismissListViewTouchListener(
                    getListView(),
                    new SwipeDismissListViewTouchListener.OnDismissCallback() {
                        public void onDismiss(ListView listView, int[] reverseSortedPositions) {
                            for (int position : reverseSortedPositions) {
                                removeCourse(adapter.getItem(position).toString());
                                adapter.remove(adapter.getItem(position));
                            }
                            adapter.notifyDataSetChanged();
                        }
                    });
    getListView().setOnTouchListener(touchListener);
    getListView().setOnScrollListener(touchListener.makeScrollListener());
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    // Restore the previously serialized activated item position.
    if (savedInstanceState != null
            && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
        setActivatedPosition(savedInstanceState
                .getInt(STATE_ACTIVATED_POSITION));
    }
}

@Override
public void onViewStateRestored(Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);
    String[] projection = { DbHelper.COURSE_NAME };
    Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
            null, null);
    c.moveToFirst();

    while (c.moveToNext()) {
        courseName = c.getString(c.getColumnIndex(DbHelper.COURSE_NAME));
        courseItems.add(courseName);
    }
    c.close();
    adapter.notifyDataSetChanged();
}

public void addCourse() {
    String[] projection = { DbHelper.COURSE_NAME };
    Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
            null, null);
    c.moveToLast();
    courseName = c.getString(c.getColumnIndex(DbHelper.COURSE_NAME));
    courseItems.add(courseName);
    c.close();
    adapter.notifyDataSetChanged();
}

public void removeCourse(String deletedCourse) {
    String[] projection = { DbHelper.COURSE_NAME };
    Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
            null, null);
    c.moveToFirst();
    while(c.moveToNext()) {
        courseName = c.getString(c.getColumnIndex(DbHelper.COURSE_NAME));
        if (deletedCourse.equals(courseName)) {
            db.delete(DbHelper.TABLE_NAME, DbHelper.C_ID + "=" + 
        db.query(DbHelper.TABLE_NAME,new String[]{DbHelper.C_ID},null,null,null,null,null),null);
        }
    }
    c.close();
}
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    // Activities containing this fragment must implement its callbacks.
    if (!(activity instanceof Callbacks)) {
        throw new IllegalStateException(
                "Activity must implement fragment's callbacks.");
    }

    mCallbacks = (Callbacks) activity;
}

@Override
public void onDetach() {
    super.onDetach();

    // Reset the active callbacks interface to the dummy implementation.
    mCallbacks = sDummyCallbacks;
}

@Override
public void onListItemClick(ListView listView, View view, int position,
        long id) {
    super.onListItemClick(listView, view, position, id);
    // Notify the active callbacks interface (the activity, if the
    // fragment is attached to one) that an item has been selected.
    mCallbacks.onItemSelected(null);

}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (mActivatedPosition != ListView.INVALID_POSITION) {
        // Serialize and persist the activated item position.
        outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
    }
}

/**
 * Turns on activate-on-click mode. When this mode is on, list items will be
 * given the 'activated' state when touched.
 */
public void setActivateOnItemClick(boolean activateOnItemClick) {
    // When setting CHOICE_MODE_SINGLE, ListView will automatically
    // give items the 'activated' state when touched.
    getListView().setChoiceMode(
            activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
                    : ListView.CHOICE_MODE_NONE);
}

public void setActivatedPosition(int position) {
    if (position == ListView.INVALID_POSITION) {
        getListView().setItemChecked(mActivatedPosition, false);
    } else {
        getListView().setItemChecked(position, true);
    }

    mActivatedPosition = position;
}
}

And here is my logcat:

12-04 16:09:30.155: E/AndroidRuntime(333): FATAL EXCEPTION: main
12-04 16:09:30.155: E/AndroidRuntime(333): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sample/com.example.sample.CourseListActivity}: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.app.ActivityThread.access$2300(ActivityThread.java:125)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.os.Handler.dispatchMessage(Handler.java:99)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.os.Looper.loop(Looper.java:123)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.app.ActivityThread.main(ActivityThread.java:4627)
12-04 16:09:30.155: E/AndroidRuntime(333):  at java.lang.reflect.Method.invokeNative(Native Method)
12-04 16:09:30.155: E/AndroidRuntime(333):  at java.lang.reflect.Method.invoke(Method.java:521)
12-04 16:09:30.155: E/AndroidRuntime(333):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
12-04 16:09:30.155: E/AndroidRuntime(333):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
12-04 16:09:30.155: E/AndroidRuntime(333):  at dalvik.system.NativeStart.main(Native Method)
12-04 16:09:30.155: E/AndroidRuntime(333): Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:582)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.view.LayoutInflater.inflate(LayoutInflater.java:385)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
12-04 16:09:30.155: E/AndroidRuntime(333):  at com.actionbarsherlock.internal.ActionBarSherlockCompat.setContentView(ActionBarSherlockCompat.java:853)
12-04 16:09:30.155: E/AndroidRuntime(333):  at com.actionbarsherlock.app.SherlockFragmentActivity.setContentView(SherlockFragmentActivity.java:262)
12-04 16:09:30.155: E/AndroidRuntime(333):  at com.example.sample.CourseListActivity.onCreate(CourseListActivity.java:55)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
12-04 16:09:30.155: E/AndroidRuntime(333):  ... 11 more
12-04 16:09:30.155: E/AndroidRuntime(333): Caused by: java.lang.IllegalStateException: Content view not yet created
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
12-04 16:09:30.155: E/AndroidRuntime(333):  at com.example.sample.CourseListFragment.onCreate(CourseListFragment.java:96)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.support.v4.app.Fragment.performCreate(Fragment.java:1437)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:877)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1066)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1168)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:280)
12-04 16:09:30.155: E/AndroidRuntime(333):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:558)
12-04 16:09:30.155: E/AndroidRuntime(333):  ... 19 more

Any help is much appreciated! Thank You!


Solution

  • You are doing to much in OnCreate() - your Fragment's view's are not yet initialized and you are trying to get ListView. Try to use OnViewCreated() or OnActivityCreated() callback.