SherlockFragmentActivity

SherlockFragmentActivity

我正在使用一个扩展sherlockfragmentactivity的活动,它有3个选项卡。这3个选项卡是实现loadermanager.loadercallbacks的ListFragments。活动的oncreate方法加载选项卡,如下所示

bar.addTab(bar.newTab()
    .setTag("venues_list")
    .setText(getString(R.string.list_venues_header))
    .setTabListener(new TabListener<VenueListFragment>(
        this, getString(R.string.list_invites_header), VenueListFragment.class, null)));

// I do the EXACT same thing for the other two tabs, using their respective ListFragments

if (savedInstanceState != null) {
    bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}

我正在加载选项卡的布局非常简单:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

</LinearLayout>

每个选项卡都有一个与此相同的类,称为不同的类:
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockListFragment;
import com.lateral.oursvp.R;
import com.lateral.oursvp.database.SimpleCursorLoader;
import com.lateral.oursvp.database.VenuesDataSource;

/**
 * @author rabbott
 *
 */
public class VenueListFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
    SharedPreferences appPreferences;

    private CursorAdapter cursorAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // bind the columns of the cursor to the list
        String[] from = new String[] { VenuesDataSource.KEY_NAME, VenuesDataSource.KEY_DESCRIPTION };
        int[] to = new int[] { R.id.list_item_title, R.id.list_item_subtitle };

        cursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.list_item, null, from, to, 0);

        // retrieve the listview to populate
        ListView lv = (ListView) getActivity().findViewById(android.R.id.list);

        // set the adapter on the listview
        lv.setAdapter(cursorAdapter);

        // click event for each row of the list
        lv.setOnItemClickListener(new OnItemClickListener() {

            public void onItemClick(AdapterView<?> arg0, View view,
                    int position, long id) {
                Cursor cursor = cursorAdapter.getCursor();
                cursor.moveToPosition(position);

                Toast.makeText(getActivity(), "Tapped row " + position + "!", Toast.LENGTH_SHORT).show();
            }
        });

        // Start out with a progress indicator.
        setListShown(false);

        // load the data
        getActivity().getSupportLoaderManager().initLoader(0, null, this);
    }

    public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
        return new VenueCursorLoader(getActivity());
    }

    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        cursorAdapter.swapCursor(cursor);

        // the list should now be shown
        if (isResumed()) {
            setListShown(true);
        } else {
            setListShownNoAnimation(true);
        }
    }

    public void onLoaderReset(Loader<Cursor> loader) {
        cursorAdapter.swapCursor(null);
    }

    public static final class VenueCursorLoader extends SimpleCursorLoader {

        Context mContext;

        public VenueCursorLoader(Context context) {
            super(context);

            mContext = context;
        }

        @Override
        public Cursor loadInBackground() {
            VenuesDataSource datasource = new VenuesDataSource(mContext);

            return datasource.getAllVenues(((EventActivity) mContext).getEventId());
        }

    }
}

使用此处定义的simplecursorloaded:
import android.content.Context;
import android.database.Cursor;
import android.support.v4.content.AsyncTaskLoader;

public abstract class SimpleCursorLoader extends AsyncTaskLoader<Cursor> {
    private Cursor mCursor;

    public SimpleCursorLoader(Context context) {
        super(context);
    }

    /* Runs on a worker thread */
    @Override
    public abstract Cursor loadInBackground();

    /* Runs on the UI thread */
    @Override
    public void deliverResult(Cursor cursor) {
        if (isReset()) {
            // An async query came in while the loader is stopped
            if (cursor != null) {
                cursor.close();
            }
            return;
        }
        Cursor oldCursor = mCursor;
        mCursor = cursor;

        if (isStarted()) {
            super.deliverResult(cursor);
        }

        if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
            oldCursor.close();
        }
    }

    /**
     * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
     * will be called on the UI thread. If a previous load has been completed and is still valid
     * the result may be passed to the callbacks immediately.
     * <p/>
     * Must be called from the UI thread
     */
    @Override
    protected void onStartLoading() {
        if (mCursor != null) {
            deliverResult(mCursor);
        }
        if (takeContentChanged() || mCursor == null) {
            forceLoad();
        }
    }

    /**
     * Must be called from the UI thread
     */
    @Override
    protected void onStopLoading() {
        // Attempt to cancel the current load task if possible.
        cancelLoad();
    }

    @Override
    public void onCanceled(Cursor cursor) {
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
    }

    @Override
    protected void onReset() {
        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();

        if (mCursor != null && !mCursor.isClosed()) {
            mCursor.close();
        }
        mCursor = null;
    }
}

我的问题是当我选择说…第二个选项卡(第三个选项卡也一样)尝试加载光标,但是当它尝试填充列表项时,我得到一个错误
E/AndroidRuntime(2055): java.lang.IllegalArgumentException: column 'GIVEN_VARIABLE' does not exist

在设置了几个断点之后,我发现它试图使用的光标是第一个选项卡中的光标,它在通货膨胀时加载得很好,但是显然没有关闭,而且很明显它试图再次使用,尽管我(认为)发送了一个不同于getal的光标Lvuu()
编辑:这是堆栈跟踪发送给我的最后一个地方
当我设置一些断点时,我可以看到这里提供的光标是第一个选项卡中的光标,而不是“地点”选项卡中的光标。
编辑:venuesdatasource代码以显示getAllVenues方法
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.util.Log;

/**
 * @author rabbott
 *
 */
public class VenuesDataSource extends appSQLiteHelper {

    public static final String TABLE_NAME               = "venues";

    // venue columns
    public static final String KEY_NAME                 = "name";
    public static final String KEY_DESCRIPTION          = "description";
    public static final String KEY_START_TIME           = "start_time";
    public static final String KEY_ADDRESS              = "address";
    public static final String KEY_CITY                 = "city";
    public static final String KEY_STATE                = "state";
    public static final String KEY_ZIP                  = "postal_code";
    public static final String KEY_LNG                  = "lng";
    public static final String KEY_LAT                  = "lat";
    public static final String KEY_PHONE                = "phone";

    public static String COLUMNS_VENUES[] = {
        DatabaseConstants.KEY_ROWID,
        DatabaseConstants.KEY_EVENT_ID,
        KEY_NAME,
        KEY_DESCRIPTION,
        KEY_START_TIME,
        KEY_ADDRESS,
        KEY_CITY,
        KEY_STATE,
        KEY_ZIP,
        KEY_LNG,
        KEY_LAT,
        KEY_PHONE,
        DatabaseConstants.KEY_CREATED_AT
    };

    public static final String CREATE_STATEMENT = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
            + "_id              INTEGER PRIMARY KEY AUTOINCREMENT,"
            + "event_id         INTEGER NOT NULL,"
            + "name             TEXT NOT NULL,"
            + "description      TEXT,"
            + "start_time       TEXT,"
            + "address          TEXT NOT NULL,"
            + "city             TEXT NOT NULL,"
            + "state            TEXT NOT NULL,"
            + "postal_code      TEXT,"
            + "lat              TEXT,"
            + "lng              TEXT,"
            + "phone            TEXT,"
            + "created_at       TEXT);";

    public VenuesDataSource(Context context) {
        super(context);

        Log.i("VenueDataSource", "Constructor");
    }

    // create a new contact locally
    public long createVenue(Integer venue_id, Integer event_id, String name, String description, String start_time, String address, String city, String state, String postal_code, String lat, String lng, String phone, String created_at) {
        ContentValues initialValues = new ContentValues();

        initialValues.put(DatabaseConstants.KEY_ROWID, event_id);
        initialValues.put(DatabaseConstants.KEY_EVENT_ID, event_id);
        initialValues.put(KEY_NAME, name);
        initialValues.put(KEY_DESCRIPTION, description);
        initialValues.put(KEY_START_TIME, start_time);
        initialValues.put(KEY_ADDRESS, address);
        initialValues.put(KEY_CITY, city);
        initialValues.put(KEY_STATE, state);
        initialValues.put(KEY_ZIP, postal_code);
        initialValues.put(KEY_PHONE, phone);
        initialValues.put(KEY_LAT, lat);
        initialValues.put(KEY_LNG, lng);
        initialValues.put(DatabaseConstants.KEY_CREATED_AT, created_at);

        return getWritableDatabase().insert(TABLE_NAME, null, initialValues);
    }

    // retrieve a venue from the local database
    public Cursor getVenue(long rowId) throws SQLException {
        Cursor mCursor = getWritableDatabase().query(true, TABLE_NAME, COLUMNS_VENUES, DatabaseConstants.KEY_ROWID + "=" + rowId, null, null, null, null, null);

        if (mCursor != null) {
            mCursor.moveToFirst();
        }

        return mCursor;
    }

    // update a local venue
    public long updateVenue(Integer venue_id, Integer event_id, String name, String description, String start_time, String address, String city, String state, String postal_code, String lat, String lng, String phone) {
        ContentValues initialValues = new ContentValues();

        initialValues.put(DatabaseConstants.KEY_EVENT_ID, event_id);
        initialValues.put(KEY_NAME, name);
        initialValues.put(KEY_DESCRIPTION, description);
        initialValues.put(KEY_START_TIME, start_time);
        initialValues.put(KEY_ADDRESS, address);
        initialValues.put(KEY_CITY, city);
        initialValues.put(KEY_STATE, state);
        initialValues.put(KEY_ZIP, postal_code);
        initialValues.put(KEY_PHONE, phone);
        initialValues.put(KEY_LAT, lat);
        initialValues.put(KEY_LNG, lng);

        return getWritableDatabase().update(TABLE_NAME, initialValues, "_id=?", new String[] { Long.toString(venue_id) });
    }

    // delete a local venue
    public boolean deleteVenue(long rowId) {
        return (getWritableDatabase().delete(TABLE_NAME, DatabaseConstants.KEY_ROWID + "=" + rowId, null) > 0);
    }

    // retrieve all local venues
    public Cursor getAllVenues(long event_id) {
        Cursor mCursor = getWritableDatabase().query(true, TABLE_NAME, COLUMNS_VENUES, DatabaseConstants.KEY_EVENT_ID + "=" + event_id,
                null, null, null, null, null);

        return mCursor;
    }

    public boolean venueExists(int venue_id) {
        Cursor mCursor = getWritableDatabase().query(true, TABLE_NAME, COLUMNS_VENUES, DatabaseConstants.KEY_ROWID + "=" + venue_id,
                    null, null, null, null, null);

        if (mCursor.getCount() == 0) {
            mCursor.close();
            return false;
        } else {
            mCursor.close();
            return true;
        }
    }

    public void parseVenue(JSONObject venueJson) throws JSONException {
        boolean venue_exists = false;

        int event_id, venue_id;
        String venue_name, venue_description, start_time, venue_address, venue_city, venue_state, venue_postal_code, lat, lng, venue_phone, created_at;

        venue_id            = venueJson.getInt(DatabaseConstants.KEY_REMOTE_ID);
        event_id            = venueJson.getInt(DatabaseConstants.KEY_EVENT_ID);
        venue_name          = venueJson.getString(KEY_NAME);
        venue_description   = venueJson.getString(KEY_DESCRIPTION);
        start_time          = venueJson.getString(KEY_START_TIME);
        venue_address       = venueJson.getString(KEY_ADDRESS);
        venue_city          = venueJson.getString(KEY_CITY);
        venue_state         = venueJson.getString(KEY_STATE);
        venue_postal_code   = venueJson.getString(KEY_ZIP);
        venue_phone         = venueJson.getString(KEY_PHONE);
        lat                 = venueJson.getString(KEY_LAT);
        lng                 = venueJson.getString(KEY_LNG);
        created_at          = venueJson.getString(DatabaseConstants.KEY_CREATED_AT);

        // check to see if this venue already exists
        venue_exists = this.venueExists(venue_id);

        if (venue_exists == true) {
            this.updateVenue(
                    venue_id,
                    event_id,
                    venue_name,
                    venue_description,
                    start_time,
                    venue_address,
                    venue_city,
                    venue_state,
                    venue_postal_code,
                    lat,
                    lng,
                    venue_phone);
        } else {
            this.createVenue(
                    venue_id,
                    event_id,
                    venue_name,
                    venue_description,
                    start_time,
                    venue_address,
                    venue_city,
                    venue_state,
                    venue_postal_code,
                    lat,
                    lng,
                    venue_phone,
                    created_at);
        }
    }

    public void parseVenues(JSONArray venuesArray) throws JSONException {
        JSONObject venueJson;

        for (int i = 0; i < venuesArray.length(); i++) {
            // Iterate through each venue
            venueJson = venuesArray.getJSONObject(i);

            this.parseVenue(venueJson);
        }
    }
}

最佳答案

问题是initloader方法的第一个参数是唯一标识要加载的每个项的方法,我的所有参数都设置为相同的(0)值——将它们更改为唯一值解决了这个问题。

关于android - 具有多个ListFragments和SQLite游标战斗的SherlockFragmentActivity,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11166032/

10-10 07:04