加载程序和内容URI不向RecyclerView

时间:2017-12-19 18:25:33

标签: java android sqlite

我正在实现内容提供程序和SQLite数据库。我已经能够向我的内容提供商添加内容,但现在我正在尝试使用Loader将该数据加载到片段的回收器视图中。

数据库定义(ClosetDbHelper.java):

public class ClosetDbHelper extends SQLiteOpenHelper
{

    private static final String DATABASE_NAME="closetsnstuff.db";
    private static final int DATABASE_VERSION = 1;

    private static final String SQL_CREATE_TABLE_CLOSETS= String.format("CREATE TABLE %s"+" (%s INTEGER PRIMARY KEY AUTOINCREMENT, %s TEXT, %s TEXT, %s TEXT)",
            DatabaseContract.TABLE_CLOSET_SHOES,
            DatabaseContract.ClosetShoesColumns._ID,
            DatabaseContract.ClosetShoesColumns.SHOE_IMAGE,
            DatabaseContract.ClosetShoesColumns.SHOE_BRAND,
            DatabaseContract.ClosetShoesColumns.SHOE_NAME);

    private final Context mContext;

    public ClosetDbHelper(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db)
    {
        db.execSQL(SQL_CREATE_TABLE_CLOSETS);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        db.execSQL("DROP TABLE IF EXISTS " + DatabaseContract.TABLE_CLOSET_SHOES);
        onCreate(db);
    }
} 

我的数据库合同(DatabaseContract.java):

public class DatabaseContract {
    public static final String TABLE_CLOSET_SHOES = "shoe_closets";

    public static final String AUTHORITY = "com.example.android.myshoecloset";
    public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + AUTHORITY);
    public static final String PATH_CLOSETS = "shoe_closets";

    public static final class ClosetShoesColumns implements BaseColumns {

        public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
                .appendPath(PATH_CLOSETS).build();

        public static final String TABLE_NAME="shoe_closets";

        //closet image
        public static final String SHOE_IMAGE = "image";
        //brand name
        public static final String SHOE_BRAND = "brand";
        //shoe name
        public static final String SHOE_NAME = "name";
    }
}

我的内容提供程序类(Provider.java):

public class Provider extends ContentProvider
{
    public static final int CLOSETS=100;
    public static final int CLOSETS_WITH_ID = 101;

    private static final UriMatcher sUriMatcher = buildUriMatcher();

    public static UriMatcher buildUriMatcher()
    {
        UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        uriMatcher.addURI(DatabaseContract.AUTHORITY, DatabaseContract.PATH_CLOSETS, CLOSETS);
        uriMatcher.addURI(DatabaseContract.AUTHORITY, DatabaseContract.PATH_CLOSETS + "/#", CLOSETS_WITH_ID);

        return uriMatcher;
    }

    private ClosetDbHelper mClosetDbHelper;

    @Override
    public boolean onCreate()
    {
        Context context = getContext();
        mClosetDbHelper = new ClosetDbHelper(context);
        return true;
    }

    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values)
    {
        final SQLiteDatabase db = mClosetDbHelper.getWritableDatabase();

        int match = sUriMatcher.match(uri);
        Uri returnUri;

        switch(match)
        {
            case CLOSETS:
                long id = db.insert(DatabaseContract.ClosetShoesColumns.TABLE_NAME, null, values);
                if(id > 0)
                {
                    returnUri = ContentUris.withAppendedId(CONTENT_URI, id);
                } else
                {
                    throw new android.database.SQLException("Failed to insert row into " + uri);
                }
                break;
            default:
                throw new UnsupportedOperationException("Unknown Uri: " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);

        return returnUri;
    }


    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {


        final SQLiteDatabase db = mClosetDbHelper.getReadableDatabase();

        int match = sUriMatcher.match(uri);

        Cursor retCursor;

        switch(match)
        {
            case CLOSETS:
                retCursor = db.query(TABLE_NAME,
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder);
                break;
            default:
                throw new UnsupportedOperationException("Unknown URI: " + uri);
        }

        retCursor.setNotificationUri(getContext().getContentResolver(), uri);

        return retCursor;

    }

}

现在我的CustomAdapter类应该从内容提供程序获取数据并将其绑定到视图:

public class CustomAdapter  extends RecyclerView.Adapter<CustomAdapter.TaskHolder> {

    /* Callback for list item click events */
    public interface OnItemClickListener {
        void onItemClick(View v, int position);

        void onItemToggled(boolean active, int position);
    }

    /* ViewHolder for each task item */
    public class TaskHolder extends RecyclerView.ViewHolder {
        public TextView shoeBrandName;
        //        public ImageView priorityView;
        public TextView shoeName;

        public TaskHolder(View itemView) {
            super(itemView);

            shoeBrandName = (TextView) itemView.findViewById(R.id.textBrandName);
//            priorityView = (ImageView) itemView.findViewById(R.id.priority);
            shoeName = (CheckBox) itemView.findViewById(R.id.textShoeName);

        }
    }

    private Cursor mCursor;
    private OnItemClickListener mOnItemClickListener;
    private Context mContext;

    public CustomAdapter(Context mContext) {
        this.mContext = mContext;
    }


    @Override
    public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        mContext = parent.getContext();
        View itemView = LayoutInflater.from(mContext)
                .inflate(R.layout.text_row_item, parent, false);

        return new TaskHolder(itemView);
    }

    @Override
    public void onBindViewHolder(TaskHolder holder, int position) {
        int idIndex = mCursor.getColumnIndex(DatabaseContract.ClosetShoesColumns._ID);
        int shoeBrandName = mCursor.getColumnIndex(DatabaseContract.ClosetShoesColumns.SHOE_BRAND);
        int shoeName = mCursor.getColumnIndex(DatabaseContract.ClosetShoesColumns.SHOE_NAME);

        mCursor.moveToPosition(position);

        final int id = mCursor.getInt(idIndex);
        String brandNameStr = mCursor.getString(shoeBrandName);
        String shoeNameStr = mCursor.getString(shoeName);


        Log.d("TAG", brandNameStr + "" + shoeNameStr);


        holder.itemView.setTag(id);
        holder.shoeBrandName.setText(brandNameStr);
        holder.shoeName.setText(shoeNameStr);

    }

    @Override
    public int getItemCount() {
        return (mCursor != null) ? mCursor.getCount() : 0;
    }


    public void swapCursor(Cursor cursor) {
        if (mCursor != null) {
            mCursor.close();
        }
        mCursor = cursor;

    }
}

最后,我有我的ClosetFragment类,我希望显示内容提供程序内容。

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.RadioButton;

import com.example.android.myshoecloset.data.DatabaseContract;


public class ClosetFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>
{
    private static final String TAG = "ClosetFragment";

    protected RecyclerView mRecyclerView;
    protected CustomAdapter mAdapter;
    private static final int CUSTOM_LOADER_ID = 0;


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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_closet, container, false);
        rootView.setTag(TAG);

        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);

        mAdapter = new CustomAdapter(getActivity().getApplicationContext());

        // Set CustomAdapter as the adapter for RecyclerView.
        mRecyclerView.setAdapter(mAdapter);
        getActivity().getSupportLoaderManager().initLoader(CUSTOM_LOADER_ID, null, (LoaderManager.LoaderCallbacks<Cursor>)this);

        return rootView;
    }

    @Override
    public void onResume()
    {
        super.onResume();
        getActivity().getSupportLoaderManager().restartLoader(CUSTOM_LOADER_ID, null, this);
    }


    @Override
    public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs)
    {
        return new AsyncTaskLoader<Cursor>(getActivity().getApplicationContext()) {
            Cursor mTaskData = null;

            @Override
            protected void onStartLoading()
            {
                if(mTaskData != null)
                {
                    deliverResult(mTaskData);
                }
                else
                {
                    forceLoad();
                }
            }

            public Cursor loadInBackground()
            {
                try
                {
                    Log.d("YES ", getActivity().getContentResolver().query(DatabaseContract.ClosetShoesColumns.CONTENT_URI, null, null, null, null)+"");
                    return getActivity().getApplicationContext().getContentResolver().query(DatabaseContract.ClosetShoesColumns.CONTENT_URI,
                            null,
                            null,
                            null,
                            null);

                } catch(Exception e)
                {
                    Log.e("", "Failed to asynchronously load data.");
                    e.printStackTrace();
                    return null;
                }
            }

            public void deliverResult(Cursor data)
            {
                mTaskData = data;
                super.deliverResult(data);
            }
        };
    }


    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data)
    {
        mAdapter.swapCursor(data);
    }
    @Override
    public void onLoaderReset(Loader<Cursor> loader)
    {
        mAdapter.swapCursor(null);
    }
}

对于代码密集的帖子感到抱歉,但对此有任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

当您将新数据交换到RecyclerView.Adapter时,您还需要调用notifyDataSetChanged(),因此适配器知道无效并重新绑定视图。

public void swapCursor(Cursor c) {
    mCursor = c;
    notifyDataSetChanged();
}

此外,我强烈建议您使用CursorLoader。它是专门为这个用例编写的。 CursorLoader也将为您关闭光标。

编辑:您的RecyclerView也缺少布局管理器。