데이터베이스와 함께 recyclerview 사용


127

현재 사용 가능한 RecyclerView.Adapter의 기본 구현은 없습니다.

공식 출시와 함께 Google이 추가 할 예정입니다.

에 대한 지원이 없기 때문에 CursorAdapter(가)와 RecyclerView현재, 어떻게 우리가 사용할 수있는 RecyclerView데이터베이스와는? 어떤 제안?

답변:


101

a로 쿼리를 실행하고 CursorLoader있고 RecyclerView대신 원하는 경우 ListView.

당신은 내 시도 할 수 있습니다 CursorRecyclerViewAdapter: RecyclerView의 CursorAdapter


12
Cursor 클래스의 registerDataSetObserver 메소드는 정확히 변경된 요소를 식별하지 않기 때문에 코드를 삭제하고 삽입 할 때 애니메이션이 작동하지 않습니다. 따라서 컨텐츠 제공자가 변경 될 때마다 notifyDataSetChanged 를 통해 recyclerview가 완전히로드 되며 이것이 RecyclerView의 본질입니다.
francas 2016 년

1
생성자를 통해 커서를 어댑터에 전달하고 onBindViewHolder ()에서 cursor.moveToPosition ()을 사용하여 관련 데이터를 가져 오는 단점은 무엇입니까?
Gautam

2
제안 : 생성자에서 전화 swapCursor (), 당신이 자신을 반복해야 해달라고 그래서
그렉 에니스

2
@francas 애니메이션 설정하면 잘 작동합니다.setHasStableIds(true)
alders

2
@alders setHasTableIds 외에 다른 변경을 했습니까? 나는 또한 ID가 일치하고 커서를 바꿀 때마다 목록이 맨 위로 이동한다는 것을 시도했습니다.
dwbrito

89

내 솔루션은 recyclerView.Adapter 구현에서 CursorAdapter 멤버를 보유하는 것이 었습니다. 그런 다음 새보기를 만들고 커서 어댑터에 바인딩하는 모든 처리를 전달하십시오.

public class MyRecyclerAdapter extends Adapter<MyRecyclerAdapter.ViewHolder> {

    // Because RecyclerView.Adapter in its current form doesn't natively 
    // support cursors, we wrap a CursorAdapter that will do all the job
    // for us.
    CursorAdapter mCursorAdapter;

    Context mContext;

    public MyRecyclerAdapter(Context context, Cursor c) {

        mContext = context;

        mCursorAdapter = new CursorAdapter(mContext, c, 0) {

            @Override
            public View newView(Context context, Cursor cursor, ViewGroup parent) {
                // Inflate the view here
            }

            @Override
            public void bindView(View view, Context context, Cursor cursor) {
                // Binding operations
            }
        };
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        View v1;

        public ViewHolder(View itemView) {
            super(itemView);
            v1 = itemView.findViewById(R.id.v1);
        }
    }

    @Override
    public int getItemCount() {
        return mCursorAdapter.getCount();
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // Passing the binding operation to cursor loader
        mCursorAdapter.getCursor().moveToPosition(position); //EDITED: added this line as suggested in the comments below, thanks :)
        mCursorAdapter.bindView(holder.itemView, mContext, mCursorAdapter.getCursor());

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Passing the inflater job to the cursor-adapter
        View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent);
        return new ViewHolder(v);
    }
}

17
이 솔루션을 주셔서 감사합니다, 그것은 나를 위해 작동, 난 그냥 onBindViewHolder에 한 줄을 추가했다 : 'mCursorAdapter.getCursor () moveToPosition (위치).'mCursorAdapter에의 Bindview ()를 호출하기 전에
user1071762

8
@nbtk CursorAdapter 대신 Cursor를 유지하지 않는 이유는 무엇입니까? 아시다시피, 당신은 CursorAdapter의 기능을 사용하지 않습니다.
MyDogTom

14
@MyDogTom-커서를 보유하지 않습니다. 완료되면 커서를 지우고 NULL로 설정하는 것만으로는 충분하지 않습니다. CursorAdapter는이를 완벽하게 처리합니다.
nbtk

3
@nbtk 저는이 아이디어가 정말 마음에 들었습니다. 나는 그것을 추상화하고 라이브러리를 만들었습니다. 아직 원하는 곳은 100 %가 아니지만 작업을 완료합니다. 그것을 확인하고 싶습니까? github이 있다면 영감으로 기뻐할 것입니다. github.com/androidessence/RecyclerViewCursorAdapter
AdamMc331 15.04에서

5
@nbtk 새 데이터로보기를 새로 고치려면 다음을 수행하십시오.public void changeCursor(Cursor cursor){ mCursorAdapter.changeCursor(cursor); notifyDataSetChanged(); }
Cijo

48

귀하의 질문에 " RecyclerView데이터베이스와 함께 사용하는 방법 "이 표시되어 있고 SQLite를 원하든 또는를 사용하여 다른 것을 원하든 구체적이지 않기 때문에 RecyclerView매우 최적의 솔루션을 제공합니다. Realm 을 데이터베이스 로 사용 하고에있는 모든 데이터를 표시하겠습니다 RecyclerView. 그것은 사용하지 않고 아니라 비동기 쿼리 지원이 Loaders또는 AsyncTask.

왜 영역? realm.io 성능 안드로이드

1 단계

Realm에 대한 gradle 종속성을 추가하십시오. 최신 버전에 대한 종속성은 여기에 있습니다.

2 단계

예를 들어, 모델 클래스를 만들면 Data2 개의 필드, RecyclerView행 내부에 표시되는 문자열 및 RecyclerView항목에 애니메이션을 적용 할 수있는 itemId로 사용되는 타임 스탬프 가 있는 간단한 것을 말할 수 있습니다. 클래스가 테이블로 저장되고 모든 속성이 해당 테이블의 열로 저장 RealmObject되므로 아래로 확장 됩니다 . 문자열을 두 번 이상 추가하지 않기 때문에 데이터 텍스트를 기본 키로 표시했습니다. 그러나 중복을 선호하는 경우 타임 스탬프를 @PrimaryKey로 만드십시오. 기본 키가없는 테이블을 가질 수 있지만 테이블을 작성한 후 행을 업데이트하려고하면 문제가 발생할 수 있습니다. 이 답변을 작성할 당시의 복합 기본 키는 Realm에서 지원하지 않습니다.DataData

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;

public class Data extends RealmObject {
@PrimaryKey
private String data;

//The time when this item was added to the database
private long timestamp;

public String getData() {
    return data;
}

public void setData(String data) {
    this.data = data;
}

public long getTimestamp() {
    return timestamp;
}

public void setTimestamp(long timestamp) {
    this.timestamp = timestamp;
}
}

3 단계

안에 단일 행이 표시되는 방식에 대한 레이아웃을 만듭니다 RecyclerView. 우리 내부의 단일 행 항목의 레이아웃 Adapter은 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<TextView
    android:id="@+id/area"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@android:color/white"
    android:padding="16dp"
    android:text="Data"
    android:visibility="visible" />

</FrameLayout>

내부 FrameLayout가 있어도 루트로 유지했습니다 TextView. 이 레이아웃에 더 많은 항목을 추가 할 계획이므로 지금은 유연하게 만들었습니다. :)

호기심 많은 사람들에게 이것이 단일 항목이 현재 어떻게 보이는지입니다. RecyclerView 내의 단일 항목 행 레이아웃

4 단계

RecyclerView.Adapter구현을 작성하십시오 . 이 경우 데이터 소스 오브젝트는 RealmResults기본적으로 LIVE 라는 특수 오브젝트입니다. ArrayList즉, 항목이 테이블에서 추가되거나 제거되면이 RealmResults오브젝트가 자동으로 업데이트됩니다.

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import io.realm.Realm;
import io.realm.RealmResults;
import slidenerd.vivz.realmrecycler.R;
import slidenerd.vivz.realmrecycler.model.Data;

public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataHolder> {
private LayoutInflater mInflater;
private Realm mRealm;
private RealmResults<Data> mResults;

public DataAdapter(Context context, Realm realm, RealmResults<Data> results) {
    mRealm = realm;
    mInflater = LayoutInflater.from(context);
    setResults(results);
}

public Data getItem(int position) {
    return mResults.get(position);
}

@Override
public DataHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = mInflater.inflate(R.layout.row_data, parent, false);
    DataHolder dataHolder = new DataHolder(view);
    return dataHolder;
}

@Override
public void onBindViewHolder(DataHolder holder, int position) {
    Data data = mResults.get(position);
    holder.setData(data.getData());
}

public void setResults(RealmResults<Data> results) {
    mResults = results;
    notifyDataSetChanged();
}

@Override
public long getItemId(int position) {
    return mResults.get(position).getTimestamp();
}

@Override
public int getItemCount() {
    return mResults.size();
}

public void add(String text) {

    //Create a new object that contains the data we want to add
    Data data = new Data();
    data.setData(text);

    //Set the timestamp of creation of this object as the current time
    data.setTimestamp(System.currentTimeMillis());

    //Start a transaction
    mRealm.beginTransaction();

    //Copy or update the object if it already exists, update is possible only if your table has a primary key
    mRealm.copyToRealmOrUpdate(data);

    //Commit the transaction
    mRealm.commitTransaction();

    //Tell the Adapter to update what it shows.
    notifyDataSetChanged();
}

public void remove(int position) {

    //Start a transaction
    mRealm.beginTransaction();

    //Remove the item from the desired position
    mResults.remove(position);

    //Commit the transaction
    mRealm.commitTransaction();

    //Tell the Adapter to update what it shows
    notifyItemRemoved(position);
}

public static class DataHolder extends RecyclerView.ViewHolder {
    TextView area;

    public DataHolder(View itemView) {
        super(itemView);
        area = (TextView) itemView.findViewById(R.id.area);
    }

    public void setData(String text) {
        area.setText(text);
    }
}
}

공지 사항 내가 전화 오전 notifyItemRemoved제거가 발생하는 위치에 있지만 내가 전화하지 마십시오 notifyItemInserted또는 notifyItemRangeChanged영역 항목이 정렬 된 방식으로 저장되지 않기 때문에 항목이 데이터베이스에 삽입 된 위치를 알 수있는 직접적인 방법이 없기 때문입니다. RealmResults객체 자동 새로운 아이템 추가, 우리가 부르는 있도록 데이터베이스에서 변경 또는 제거 될 때마다 업데이트 notifyDataSetChanged추가 및 삽입하는 동안 대량의 항목을. 이 시점에서 메소드 notifyDataSetChanged대신 호출하기 때문에 트리거되지 않는 애니메이션에 대해 우려하고있을 것입니다 notifyXXX. 그렇기 때문에 getItemId메소드가 결과 객체에서 각 행의 타임 스탬프를 반환하도록 하는 이유 입니다. notifyDataSetChanged호출 setHasStableIds(true)한 다음 무시 하면 2 단계로 애니메이션을 얻을 수 있습니다.getItemId 위치 이외의 다른 것을 제공합니다.

5 단계

또는에 추가 할 RecyclerView수 있습니다. 제 경우에는을 사용하고 있습니다. 를 포함하는 레이아웃 파일 은 매우 간단하며 다음과 같습니다.ActivityFragmentActivityRecyclerView

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/text_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

나는를 추가 한 app:layout_behavior내 이후 RecyclerView돌며 간다 CoordinatorLayout나는 간결이 대답에 게시하지 않은있다.

6 단계

를 구축 RecyclerView코드에서하고 필요한 데이터를 제공합니다. Realm 객체를 생성하고 초기화하고 인스턴스를 닫는 것처럼 내부 onCreate를 닫습니다 . 간단한 당신에 내부는 다음과 같이 표시됩니다. 이 방법은 모든 마술이 일어나는 곳입니다. 내부 Realm 인스턴스를 엽니 다 .onDestroySQLiteOpenHelperonCreateActivityinitUionCreate

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mRealm = Realm.getInstance(this);
    initUi();
}

private void initUi() {

    //Asynchronous query
    RealmResults<Data> mResults = mRealm.where(Data.class).findAllSortedAsync("data");

    //Tell me when the results are loaded so that I can tell my Adapter to update what it shows
    mResults.addChangeListener(new RealmChangeListener() {
        @Override
        public void onChange() {
            mAdapter.notifyDataSetChanged();
            Toast.makeText(ActivityMain.this, "onChange triggered", Toast.LENGTH_SHORT).show();
        }
    });
    mRecycler = (RecyclerView) findViewById(R.id.recycler);
    mRecycler.setLayoutManager(new LinearLayoutManager(this));
    mAdapter = new DataAdapter(this, mRealm, mResults);

    //Set the Adapter to use timestamp as the item id for each row from our database
    mAdapter.setHasStableIds(true);
    mRecycler.setAdapter(mAdapter);
}

첫 번째 단계에서 Realm에 쿼리하여 Data클래스의 모든 객체를 변수라는 이름으로 정렬 된 데이터를 비동기 방식으로 제공합니다. 이것은 RealmResults메인 스레드에 0 항목이 있는 객체를 제공 합니다 Adapter. 내 RealmChangeListener호출하는 백그라운드 스레드에서 데이터로드가 완료되면 알림을 받으려면를 추가했습니다 . 또한 구현에서 추가, 제거 또는 수정 된 항목을 추적 할 수 있도록 true로 호출 했습니다 . 제에 대한 닫는 영역 인스턴스notifyDataSetChangedAdaptersetHasStableIdsRecyclerView.AdapteronDestroyActivity

@Override
protected void onDestroy() {
    super.onDestroy();
    mRealm.close();
}

이 방법은 initUi내부에서 호출 할 수 있습니다 onCreate당신의 ActivityonCreateView또는 onViewCreated당신의 Fragment. 다음 사항에 유의하십시오.

7 단계

밤! 귀하는 내부 데이터베이스에서 데이터가 RecyclerViewasynchonously없이로드 CursorLoader, CursorAdapter, SQLiteOpenHelper애니메이션과 함께. 여기에 표시된 GIF 이미지는 다소 지연되지만 항목을 추가하거나 제거 할 때 애니메이션이 발생합니다.

RecyclerView 내부의 데이터베이스 데이터


포괄적 인 예를 제공해 주셔서 감사합니다. 몇 가지 질문이 있습니다. 영역에 비트 맵을 저장하고 싶습니까? 그렇다면 열 유형은 무엇이고 어떻게 저장하고 검색합니까?
Rakesh

1
@Rakesh는 데이터베이스에 이미지를 저장하지 않고 항상 파일 시스템에 이미지를 저장하고 데이터베이스에 이미지의 URI를 저장합니다
PirateApp

빠른 답변 감사합니다. 연락처의 이미지를 저장하려는 앱을 만들고 있습니다. 파일 시스템에 저장하는 경우 수백 개의 이미지가있을 수 있습니다. 파일 시스템에서 해당 이미지를 어떻게 관리합니까?
Rakesh

9
Realm의 인서트 성능 그래프를 포함한 FWIW는 리사이클
러뷰 (반드시

툴바에 Vivz 라고 말하면 이것이 @slidenerd 솔루션입니까?
SymbolixAU

1

필요한 모든 메소드를 직접 구현할 수 있습니다. 최근에 CursorAdapter에서 붙여 넣기 코드를 복사하여 직접 구현했습니다.

public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {

        protected boolean mDataValid;
        protected boolean mAutoRequery;
        protected Cursor mCursor;
        protected Context mContext;
        protected int mRowIDColumn;
        protected ChangeObserver mChangeObserver;
        protected DataSetObserver mDataSetObserver;
        protected FilterQueryProvider mFilterQueryProvider;
        public static final int FLAG_AUTO_REQUERY = 0x01;
        public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02;

        public Cursor getCursor() {
            return mCursor;
        }

        //Recommended
        public MyAdapter(Context context, Cursor c, int flags) {
            init(context, c, flags);
        }

        public MyAdapter(Context context, Cursor c) {
            init(context, c, FLAG_AUTO_REQUERY);
        }

        public MyAdapter(Context context, Cursor c, boolean autoRequery) {
            init(context, c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER);
        }

        void init(Context context, Cursor c, int flags) {
            if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) {
                flags |= FLAG_REGISTER_CONTENT_OBSERVER;
                mAutoRequery = true;
            } else {
                mAutoRequery = false;
            }
            boolean cursorPresent = c != null;
            mCursor = c;
            mDataValid = cursorPresent;
            mContext = context;
            mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
            if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
                mChangeObserver = new ChangeObserver();
                mDataSetObserver = new MyDataSetObserver();
            } else {
                mChangeObserver = null;
                mDataSetObserver = null;
            }

            if (cursorPresent) {
                if (mChangeObserver != null) c.registerContentObserver(mChangeObserver);
                if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver);
            }
        }

        // Create new views (invoked by the layout manager)
        @Override
        public ViewHolder onCreateViewHolder(final ViewGroup parent,
                                             int viewType) {
            // create a new view
            final View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_item, parent, false);
            // set the view's size, margins, paddings and layout parameters

            ViewHolder vh = new ViewHolder(view, mCursor, new ViewHolder.IMyViewHolderClicks() {

                @SuppressLint("NewApi")
                @Override
                public void onClick(Cursor cursor) {
                    Log.e("Item :", cursor.getString(cursor.getColumnIndex(MyDatabaseHelper.MW_NAAM)));
                    Intent intent = new Intent(TasksListFragment.this.getActivity(), DetailActivity.class);
                    intent.putExtra(DetailActivity.EXTRA_PARAM_ID, cursor.getLong(cursor.getColumnIndex(MyDatabaseHelper.MW_ID)));

                    ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
                            TasksListFragment.this.getActivity(),

                            // Now we provide a list of Pair items which contain the view we can transitioning
                            // from, and the name of the view it is transitioning to, in the launched activity
                            new Pair<View, String>(
                                    view.findViewById(R.id.imageview_item),
                                    DetailActivity.VIEW_NAME_HEADER_IMAGE),
                            new Pair<View, String>(
                                    view.findViewById(R.id.textview_name),
                                    DetailActivity.VIEW_NAME_HEADER_TITLE)
                    );

                    // Now we can start the Activity, providing the activity options as a bundle
                    startActivity(intent, activityOptions.toBundle());
                    // END_INCLUDE(start_activity)
                }
            });
            return vh;
        }

        // Replace the contents of a view (invoked by the layout manager)
        @SuppressLint("NewApi")
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            // - get element from your dataset at this position
            // - replace the contents of the view with that element
            final Cursor cursor = getItem(position);

            holder.mTextView.setText(cursor.getString(cursor.getColumnIndex(MyDatabaseHelper.MW_NAAM)));
            holder.mImageView.setTransitionName("grid:image:" + cursor.getLong(cursor.getColumnIndex(MyDatabaseHelper.MW_ID)));
            holder.mTextView.setTransitionName("grid:name:" + cursor.getLong(cursor.getColumnIndex(MyDatabaseHelper.MW_ID)));
        }

        //@Override
        // public View getView(int position, View view, ViewGroup viewGroup) {
        //     return view;
        // }

        // Return the size of your dataset (invoked by the layout manager)
        @Override
        public int getItemCount() {
            return getCount();
        }

        public int getCount() {
            if (mDataValid && mCursor != null) {
                return mCursor.getCount();
            } else {
                return 0;
            }
        }

        public Cursor getItem(int position) {
            if (mDataValid && mCursor != null) {
                mCursor.moveToPosition(position);
                return mCursor;
            } else {
                return null;
            }
        }

        @Override
        public long getItemId(int position) {
            if (mDataValid && mCursor != null) {
                if (mCursor.moveToPosition(position)) {
                    return mCursor.getLong(mRowIDColumn);
                } else {
                    return 0;
                }
            } else {
                return 0;
            }
        }

        public Cursor swapCursor(Cursor newCursor) {
            if (newCursor == mCursor) {
                return null;
            }
            Cursor oldCursor = mCursor;
            if (oldCursor != null) {
                if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
                if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
            }
            mCursor = newCursor;
            if (newCursor != null) {
                if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
                if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
                mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
                mDataValid = true;
                // notify the observers about the new cursor
                notifyDataSetChanged();
            } else {
                mRowIDColumn = -1;
                mDataValid = false;
                // notify the observers about the lack of a data set
                notifyDataSetInvalidated();
            }
            return oldCursor;
        }

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

        public CharSequence convertToString(Cursor cursor) {
            return cursor == null ? "" : cursor.toString();
        }

        public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
            if (mFilterQueryProvider != null) {
                return mFilterQueryProvider.runQuery(constraint);
            }
            return mCursor;
        }


        public FilterQueryProvider getFilterQueryProvider() {
            return mFilterQueryProvider;
        }

        public void setFilterQueryProvider(FilterQueryProvider filterQueryProvider) {
            mFilterQueryProvider = filterQueryProvider;
        }

        protected void onContentChanged() {
            if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
                if (false) Log.v("Cursor", "Auto requerying " + mCursor + " due to update");
                mDataValid = mCursor.requery();
            }
        }

        private class ChangeObserver extends ContentObserver {
            public ChangeObserver() {
                super(new Handler());
            }

            @Override
            public boolean deliverSelfNotifications() {
                return true;
            }

            @Override
            public void onChange(boolean selfChange) {
                onContentChanged();
            }
        }

        private class MyDataSetObserver extends DataSetObserver {
            @Override
            public void onChanged() {
                mDataValid = true;
                notifyDataSetChanged();
            }

            @Override
            public void onInvalidated() {
                mDataValid = false;
                notifyDataSetInvalidated();
            }
        }


        private final DataSetObservable mDataSetObservable = new DataSetObservable();

        public void registerDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.registerObserver(observer);
        }

        public void unregisterDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.unregisterObserver(observer);
        }

        public void notifyDataSetInvalidated() {
            mDataSetObservable.notifyInvalidated();
        }
    }

이 클래스의 로더는 어디에 있습니까?
IgorGanapolsky 2014

로더는이 어댑터를 사용합니다. 로더 사용 방법에 대한 예제는 developer.android.com/guide/components/loaders.html 을 참조하십시오 . 이 예에서 SimpleCursorAdapter는 MyAdapter 것
아르노

SimpleCursorAdapter은 무슨 뜻인가요? RecyclerView.Adapter를 확장하고 있습니다.
IgorGanapolsky

1
예제에서 SimpleCursorAdapter가 표시되면 MyAdapter를 대신 사용할 수 있습니다. swapcursor 메소드와 다른 메소드가있는 한 확장하는 어댑터는 중요하지 않습니다.
Arno

위의 @nbtk 답변과 비교하면 약간의 오버 코딩이있는 것 같습니다.
eRaisedToX


1

내가 받아 들인 것을 좋아하지 않기 때문에 또 다른 대답입니다 (이모는 직관적 인 사용법이 아닙니다).

다음은 제 자신의 구현으로, 다음과 매우 유사하며 부분적으로 영향을받습니다 SimpleCursorAdapter.

public class RecyclerViewSimpleCursorAdapter extends RecyclerView.Adapter {
    private int mLayout;
    private Cursor mCursor;
    private String[] mFrom;
    private int[] mTo;

    private boolean mAutoRequery;
    private ContentObserver mContentObserver;

    /**
     * Standard constructor.
     *
     * @param layout resource identifier of a layout file that defines the views for this list item. The layout file should include at least those named views defined in "to"
     * @param c      The database cursor. Can be null if the cursor is not available yet.
     * @param from   A list of column names representing the data to bind to the UI. Can be null if the cursor is not available yet.
     * @param to     The views that should display column in the "from" parameter. These should all be TextViews and ImageViews. The first N views in this list are given the values of the first N columns in the from parameter. Can be null if the cursor is not available yet.
     */
    public RecyclerViewSimpleCursorAdapter(int layout, Cursor c, String[] from, int[] to, boolean autoRequery) {
        mLayout = layout;
        mCursor = c;
        mFrom = from;
        mTo = to;
        mAutoRequery = autoRequery;

        if (mAutoRequery) {
            initializeContentObserver();
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new RecyclerView.ViewHolder(
                LayoutInflater.from(parent.getContext())
                        .inflate(mLayout, parent, false)
        ) {
        };
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        mCursor.moveToPosition(position);

        if (mFrom == null || mTo == null)
            return;

        for (int i = 0; i < mFrom.length && i < mTo.length; i++) {
            String from = mFrom[i];
            int columnIndex = mCursor.getColumnIndex(from);
            String value = mCursor.getString(columnIndex);
            View view = holder.itemView.findViewById(mTo[i]);

            if (view instanceof TextView) {
                ((TextView) view).setText(value);
            } else if (view instanceof ImageView) {
                try {
                    ((ImageView) view).setImageResource(Integer.parseInt(value));
                } catch (NumberFormatException nfe) {
                    ((ImageView) view).setImageURI(Uri.parse(value));
                }
            } else {
                throw new IllegalStateException(view.getClass().getName() + " is not a view that can be bound by this RecyclerViewSimpleCursorAdapter");
            }
        }
    }

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

    private void initializeContentObserver() {
        mContentObserver = new ContentObserver(new Handler()) {
            @Override
            public boolean deliverSelfNotifications() {
                return true;
            }

            @Override
            public void onChange(boolean selfChange) {
                notifyDataSetChanged();
            }
        };
        mCursor.registerContentObserver(mContentObserver);
    }

    /**
     * Change the underlying cursor to a new cursor. If there is an existing cursor it will be closed.
     *
     * @param cursor The new cursor to be used
     */
    public void changeCursor(Cursor cursor) {
        Cursor oldCursor = mCursor;
        if (mAutoRequery) {
            if (mCursor != null) {
                mCursor.unregisterContentObserver(mContentObserver);
            }

            mContentObserver = new ContentObserver(new Handler()) {
                @Override
                public boolean deliverSelfNotifications() {
                    return true;
                }

                @Override
                public void onChange(boolean selfChange) {
                    notifyDataSetChanged();
                }
            };

            mCursor = cursor;
            if (mCursor != null) {
                mCursor.registerContentObserver(mContentObserver);
            }
        }

        notifyDataSetChanged();

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

    /**
     * Change the cursor and change the column-to-view mappings at the same time.
     *
     * @param cursor The database cursor. Can be null if the cursor is not available yet.
     * @param from A list of column names representing the data to bind to the UI. Can be null if the cursor is not available yet.
     * @param to The views that should display column in the "from" parameter. These should all be TextViews or ImageViews. The first N views in this list are given the values of the first N columns in the from parameter. Can be null if the cursor is not available yet.
     */
    public void changeCursorAndColumns(Cursor cursor, String[] from, int[] to) {
        mFrom = from;
        mTo = to;
        changeCursor(cursor);
    }

    /**
     * Returns the cursor.
     * @return the cursor
     */
    public Cursor getCursor() {
        return mCursor;
    }
}

다른 특정 용도에 맞게 수정할 수 있지만 커서가있는 SimpleCursorAdapter경우와 마찬가지로 작동 합니다 RecyclerView.


0

DB에서 데이터를 검색하고 목록에 저장 한 후에는 다음과 같아야합니다.

    dbHelper = new BooksDbAdapter(this);
    dbHelper.open();
    //Clean all data
    dbHelper.deleteAllZist();
    //Add some data
    dbHelper.insertSomeRecords();
    List<String> mylist = dbHelper.getArrayColumn(3);

recyclerview에 데이터 추가

list = new ArrayList<DataObject>();
 Integer i=0;
    for (String lst : mylist) {
        list.add(i++, new DataObject(lst,
                "The RecyclerView widget is a more advanced and flexible 
               version of ListView."));
    }

    recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
    recyclerView.setHasFixedSize(true);
    myRecAdapter = new RecyclerviewAdapter(list, Zist1ChapterActivity.this);

0

아래는 recyclerview에 대한 cursoradapter 구현입니다. OnItemClickListener, OnLongItemClickListener, OnfooterClickListener, Sections 및 footer를 지원합니다. , 헤더, onHeaderClickListner, 빠른 스크롤러, 고정 헤더 또는 고정 섹션을 지원하지 않습니다 .

이 어댑터를 확장하고 나만의 어댑터를 만드십시오. 제공된 방법을 재정의하십시오. OnCursorLoadFinished 메소드에서 커서를 전달합니다. 어댑터가 이미 작성된 경우 swapCursor ()

package com.tracker.paisa;

import android.database.Cursor;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;


/**
 * @author Rahul Upadhyay (https://github.com/devDroidRaul)
 * Supports footer
 * Onitemclicklistener, OnItemLongClickListener, OnFooterClickListener
 * Supports Sections.
 *
 * Does Not support,Header, OnHeaderClickListener, FastScroller, StickySection (this can b done with item decor)
 * Pull requests are welcome for improvements.
 *
 * Override this to give logic to place subheaders between items.
 * public abstract boolean onPlaceSubheaderBetweenItems(int position);
 *
 * create seperate viewHolders for item, subheaders and footer. and return required views.
 *
 * @Override below methods for individual item type.
 * public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType);
 * public abstract SH onCreateSubheaderViewHolder(ViewGroup parent, int viewType);
 * public abstract FH onCreateFooterViewHolder(ViewGroup parent, int viewType);
 *
 * Bind your views with data here.
 * @Override below methods to bind data to individual item types.
 * public abstract void onBindSubHeaderViewHolder(SH holder, Cursor cursor);
 * public abstract void onBindItemViewHolder(VH holder, Cursor cursor);
 * public abstract void onBindFooterViewHolder(FH holder, int itemPosition);
 *
 * Item type -1,-2,-3 are reserved, kindly do not pass them in getItemViewType.
 */

public abstract class RecyclerViewCursorAdapter<SH extends RecyclerView.ViewHolder, VH extends RecyclerView.ViewHolder, FH extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public static final String TAG = RecyclerViewCursorAdapter.class.getSimpleName();

    private static final int TYPE_SECTION_HEADER = -1;

    private static final int TYPE_MAIN_HEADER = -2;
    private static final int TYPE_FOOTER = -3;

   // private int headerLayout=0,viewLayout=0;
    boolean createHeader;

    private List<Integer> subheaderPositions = new ArrayList<>();

    private Cursor mCursor;
    private boolean mDataValid,footerRequired=false;
    private int mRowIDColumn;
    private SparseBooleanArray mSelectedItemsIds;



   // public RecyclerViewCursorAdapter() { }

    //constructor
    public RecyclerViewCursorAdapter(Cursor c,boolean footerRequired) {
        setHasStableIds(true);
        swapCursor(c);
        this.footerRequired = footerRequired;

        this.mSelectedItemsIds = new SparseBooleanArray();
    }



    // interface for listning click on recycler view;
    public interface OnItemClickedListener{
        void OnItemClick(int id, Object data);

        void onItemLongClick(int id);
    }

    OnItemClickedListener onItemClickedListener;

    public void setOnItemClickedListener(OnItemClickedListener onItemClickedListener) {
        this.onItemClickedListener = onItemClickedListener;
    }

    public interface OnFooterClickedListener{
        void onFooterClick(Object data);
    }

    OnFooterClickedListener onFooterClickedListener;
    public void setOnFooterClickedListener( OnFooterClickedListener onFooterClickedListener){
        this.onFooterClickedListener = onFooterClickedListener;
    }

    public interface OnHeaderClickedListener{
        void onHeaderClick(Object data);
    }

    OnHeaderClickedListener onHeaderClickedListener;
    public void setOnHeaderClickedListener( OnHeaderClickedListener onHeaderClickedListener){
        this.onHeaderClickedListener = onHeaderClickedListener;
    }

    private void initSubheaderPositions() {
        subheaderPositions.clear();

        if(getItemSize() != 0) {
            //TODO:Handle This please.
            //subheaderPositions.add(0);
        } else {
            return;
        }

        for(int i = 1; i < getItemSize(); i++) {
            if(onPlaceSubheaderBetweenItems(i - 1)) {
                subheaderPositions.add(i + subheaderPositions.size());
            }
        }
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {

            initSubheaderPositions();



    }

    /**
     * Called when adapter needs to know whether to place subheader between two neighboring
     * items.
     *
     * @return true if you want to place subheader between two neighboring
     * items.
     */
    public abstract boolean onPlaceSubheaderBetweenItems(int position);

    public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType);

    public abstract SH onCreateSubheaderViewHolder(ViewGroup parent, int viewType);

    public abstract FH onCreateFooterViewHolder(ViewGroup parent, int viewType);

    public abstract void onBindSubHeaderViewHolder(SH holder, Cursor cursor);

    public abstract void onBindItemViewHolder(VH holder, Cursor cursor);

    public abstract void onBindFooterViewHolder(FH holder, int itemPosition);






    public abstract int getItemSize();

    /**
     * Return the view type of the item at position for the purposes
     * of view recycling.
     * Don't return -1. It's reserved for subheader view type.
     */
    public int getViewType(int position) {
        return 0;
    }

    @Override
    public final int getItemViewType(int position) {

        if(isSubheaderOnPosition(position)) {
            return TYPE_SECTION_HEADER;
        } if(footerRequired && getCursor().getPosition()==(getCursor().getCount()-1)){
            return TYPE_FOOTER;
        }else {
            return getViewType(position);
        }
    }

    public boolean isFooterAdded(){
        return footerRequired;
    }
    @Override
    public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d("RVCA-OCVH","create viewholder");
        if(viewType == TYPE_SECTION_HEADER) {
            return onCreateSubheaderViewHolder(parent, viewType);
        } if(footerRequired&&viewType == TYPE_FOOTER){
            return onCreateFooterViewHolder(parent, viewType);
        }else {
            return onCreateItemViewHolder(parent, viewType);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        Log.d("RVCA-OBVH","bind viewholder");
        Log.d("RVCA-OBVH","subheader position:"+isSubheaderOnPosition(position));
        if(isSubheaderOnPosition(position)) {
            if (!mDataValid) {
                throw new IllegalStateException("Cannot bind viewholder when cursor is in invalid state.");
            }
            if (!mCursor.moveToPosition(getItemPositionForViewHolder(position))) {
                throw new IllegalStateException("Could not move cursor to position " + getItemPositionForViewHolder(position) + " when trying to bind viewholder");
            }

            onBindSubHeaderViewHolder((SH)holder, mCursor);
        }if(footerRequired && position==getItemCount()-1){
            Log.d("RVCA-OBVH","bind footerHolder");
            onBindFooterViewHolder((FH) holder,position);

        } else {
            if (!mDataValid) {
                throw new IllegalStateException("Cannot bind viewholder when cursor is in invalid state.");
            }
            if (!mCursor.moveToPosition(getItemPositionForViewHolder(position))) {
                throw new IllegalStateException("Could not move cursor to position " + getItemPositionForViewHolder(position) + " when trying to bind viewholder");
            }
            // if(!mCursor.isAfterLast()) {
            //   mCursor.moveToPosition(position);
            onBindItemViewHolder((VH)holder, mCursor);

        }
    }

    @Override
    public final int getItemCount() {
        return getItemSize() + subheaderPositions.size()+(footerRequired?1:0);
    }

    public void notifyDataChanged() {
        initSubheaderPositions();
        notifyDataSetChanged();
    }

    public void notifyItemInsertedAtPosition(int itemPosition) {
        if (itemPosition == 0) {
            if (getItemCount() == 1 || onPlaceSubheaderBetweenItems(itemPosition)) {
                subheaderPositions.add(0, 0);
                increaseSubheaderPositions(1, 2);
                notifyItemRangeInserted(0, 2);
            } else {
                increaseSubheaderPositions(1, 1);
                notifyItemInserted(1);
            }
        } else if (itemPosition == getItemSize() - 1) {
            if (onPlaceSubheaderBetweenItems(itemPosition - 1)) {
                subheaderPositions.add(getItemCount() - 1);
                notifyItemRangeInserted(getItemCount() - 1, 2);
            } else {
                notifyItemInserted(getItemPositionInRecyclerView(itemPosition));
            }
        } else {
            if (onPlaceSubheaderBetweenItems(itemPosition - 1) && onPlaceSubheaderBetweenItems(itemPosition)) {
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition - 1);
                final int countOfSubheadersBeforePosition = getCountOfSubheadersBeforePosition(itemPositionInRv);
                subheaderPositions.add(countOfSubheadersBeforePosition, itemPositionInRv + 1);
                increaseSubheaderPositions(countOfSubheadersBeforePosition + 1, 2);
                notifyItemRangeInserted(itemPositionInRv + 1, 2);
            } else if (onPlaceSubheaderBetweenItems(itemPosition)){
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition - 1);
                increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1);
                notifyItemInserted(itemPositionInRv + 1);
            } else if (onPlaceSubheaderBetweenItems(itemPosition - 1)) {
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);
                increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1);
                notifyItemInserted(itemPositionInRv);
            } else {
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);
                increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1);
                notifyItemInserted(itemPositionInRv);
            }
        }
    }

    public void notifyItemChangedAtPosition(int itemPosition) {
        final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);
        notifyItemChanged(itemPositionInRv);
    }

    public void notifyItemRemovedAtPosition(int itemPosition) {

        final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);

        for (int i = 1; i < subheaderPositions.size(); i++) {
            final int subheaderPosition = subheaderPositions.get(i);
            if (subheaderPosition > itemPositionInRv) {
                final int previousSubheaderPosition = subheaderPositions.get(i - 1);
                if (subheaderPosition - previousSubheaderPosition == 2) {
                    subheaderPositions.remove(subheaderPositions.indexOf(previousSubheaderPosition));
                    decreaseSubheaderPositions(subheaderPositions.indexOf(subheaderPosition), 2);
                    notifyItemRangeRemoved(itemPositionInRv - 1, 2);
                } else {
                    decreaseSubheaderPositions(subheaderPositions.indexOf(subheaderPosition), 1);
                    notifyItemRemoved(itemPositionInRv);
                }
                return;
            }
        }

        final int lastSubheaderPosition = subheaderPositions.get(subheaderPositions.size() - 1);
        if (itemPositionInRv - lastSubheaderPosition == 1 && getItemCount() == itemPosition + subheaderPositions.size()) {
            subheaderPositions.remove(subheaderPositions.size() - 1);
            notifyItemRangeRemoved(itemPositionInRv - 1, 2);
        } else {
            notifyItemRemoved(itemPositionInRv);
        }
    }

    public void setGridLayoutManager(final GridLayoutManager gridLayoutManager) {
        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                if(subheaderPositions.contains(position)) {
                    return gridLayoutManager.getSpanCount();
                } else {
                    return 1;
                }
            }
        });
    }

    public boolean isSubheaderOnPosition(int position) {
        return subheaderPositions.contains(position);
    }

    public int getCountOfSubheadersBeforePosition(int position) {
        int count = 0;
        for(int subheaderPosition : subheaderPositions) {
            if(subheaderPosition < position) {
                count++;
            }
        }
        return count;
    }

    public int getItemPositionInRecyclerView(int position) {
        int countOfItems = 0;
        for (int i = 1; i < subheaderPositions.size(); i++) {
            final int previousSubheaderPosition = subheaderPositions.get(i - 1);
            final int nextSubheaderPosition = subheaderPositions.get(i);
            countOfItems += nextSubheaderPosition - previousSubheaderPosition - 1;
            if (countOfItems > position) {
                return position + i;
            }
        }
        return position + subheaderPositions.size();
    }

    public int getItemPositionForViewHolder(int viewHolderPosition) {
        return viewHolderPosition - getCountOfSubheadersBeforePosition(viewHolderPosition);
    }

    private void decreaseSubheaderPositions(int startSubheaderPosition, int decreaseNum) {
        for (int i = startSubheaderPosition; i < subheaderPositions.size(); i++) {
            final int subheaderPosition = subheaderPositions.get(i);
            subheaderPositions.set(i, subheaderPosition - decreaseNum);
        }
    }

    private void increaseSubheaderPositions(int startSubheaderPosition, int increaseNum) {
        for (int i = startSubheaderPosition; i < subheaderPositions.size(); i++) {
            final int subheaderPosition = subheaderPositions.get(i);
            subheaderPositions.set(i, subheaderPosition + increaseNum);
        }
    }

    private List<Integer> getSubheaderPositions() {
        return subheaderPositions;
    }

    public int getSubheaderCount() {
        return subheaderPositions.size();
    }

    public void swapCursor(Cursor newCursor) {
        Log.d("RVCA-SC","swap cursor");
        if (newCursor == mCursor) {
            Log.d("RVCA-SC","same cursor doing nothing");
            return;
        }

        if (newCursor != null) {
            Log.d("RVCA-SC","swap cursor not null");
            mCursor = newCursor;
            mRowIDColumn = mCursor.getColumnIndexOrThrow("_id");
            mDataValid = true;

            // notify the observers about the new cursor
            notifyDataChanged();
        } else {
            Log.d("RVCA-SC","swap cursor null");
            notifyItemRangeRemoved(0, getItemCount());
            mCursor = null;
            mRowIDColumn = -1;
            mDataValid = false;
        }
    }

    public Cursor getCursor(){
        return mCursor ;
    }

    @Override
    public long getItemId(int position) {
        if (isSubheaderOnPosition(position))
            return position;
        else {
            int cursorPosition = getItemPositionForViewHolder(position);
            Cursor cursor = getCursor();
            if (hasOpenCursor() && cursor.moveToPosition(cursorPosition)) {
                return cursor.getLong(cursor.getColumnIndex("_id"));
            }
            return NO_CURSOR_POSITION;
        }
    }
    public static final int NO_CURSOR_POSITION = -99;

    protected boolean hasOpenCursor() {
        Cursor cursor = getCursor();
        if (cursor == null || cursor.isClosed()) {
            swapCursor(null);
            return false;
        }
        return true;
    }

    //Methods to do Selection

    public void toggleSelection(int position) {
        selectView(position, !mSelectedItemsIds.get(position));
    }


    //Remove selected selections
    public void removeSelection() {
        mSelectedItemsIds = new SparseBooleanArray();
        notifyDataSetChanged();
    }


    //Put or delete selected position into SparseBooleanArray
    public void selectView(int position, boolean value) {
        if (value)
            mSelectedItemsIds.put(position, value);
        else
            mSelectedItemsIds.delete(position);

        // notifyItemChangedAtPosition(position);
        notifyDataSetChanged();
    }

    //Get total selected count
    public int getSelectedCount() {
        return mSelectedItemsIds.size();
    }

    //Return all selected ids
    public SparseBooleanArray getSelectedIds() {
        return mSelectedItemsIds;
    }

    public void setSelectedItemIds(SparseBooleanArray selectedItemIds){
        this.mSelectedItemsIds=selectedItemIds;
    }


}

0

가장 간단한 구현은 어댑터에서 커서 객체를 사용하고 뷰를 수정하기 위해 커서를 뷰 홀더 생성자에 전달하고 onBindViewholder에서 커서 위치를 변경하는 것입니다.

커서 로더를 사용하는 경우 setCursor 메소드를 호출하고 onLoadfinished()null을 전달하십시오.onLoadReset()

public class PetCursorRecyclerViewAdapter extends RecyclerView.Adapter<PetCursorRecyclerViewAdapter.ViewHolder> {
Cursor cursor = null;
Context context;

public PetCursorRecyclerViewAdapter(Context context) {
    this.context = context;

}

public void setCursor(Cursor cursor) {
    this.cursor = cursor;
    notifyDataSetChanged();
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(context).inflate(R.layout.catalog_item, parent, false);
    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    this.cursor.moveToPosition(position);
    holder.bindModel(this.cursor);
}

/*   getItemCount() returns the count of videos from the Cursor, or 0 if the
   Cursor is null (mimicking the behavior of CursorAdapter, which also treats
   a null Cursor as merely being one that has no rows)*/
@Override
public int getItemCount() {
    if (cursor == null) {
        return 0;
    } else {
        return cursor.getCount();
    }
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    private TextView name_tv, breed_tv;

    public ViewHolder(View itemView) {
        super(itemView);
        name_tv = (TextView) itemView.findViewById(R.id.name_tv);
        breed_tv = (TextView) itemView.findViewById(R.id.breed_tv);
    }

    public void bindModel(Cursor cursor) {
        int name_index = cursor.getColumnIndexOrThrow(PetsContract.PetEntry.COLUMN_PET_NAME);
        int breed_index = cursor.getColumnIndexOrThrow(PetsContract.PetEntry.COLUMN_PET_BREED);
        name_tv.setText(cursor.getString(name_index));
        String breed = cursor.getString(breed_index);
        if (TextUtils.isEmpty(breed)) {
            breed = "Unknown Breed";
        }
        breed_tv.setText(breed);
    }
}    

}


0

마지막으로 데이터베이스 / 네트워크 용 RecyclerView.Adapter를 구현했습니다.

그것은 안드로이드 아키텍처 구성 요소로 실현되었습니다 :

회의실 데이터베이스 : SQLite 데이터베이스 상단의 데이터베이스 계층은로 처리하는 데 일상적인 작업을 처리합니다 SQLiteOpenHelper. 기본 SQLite 데이터베이스에 대한 액세스 지점 역할을하는 데이터베이스 홀더 Room 데이터베이스는 DAO를 사용하여 SQLite 데이터베이스에 쿼리를 발행합니다.

ViewModel : UI에 데이터를 제공합니다. 리포지토리와 UI 간의 커뮤니케이션 센터 역할을합니다. UI에서 데이터가 시작된 위치를 숨 깁니다. ViewModel 인스턴스는 Activity / Fragment 레크리에이션 후에도 유지됩니다.

LiveData : 관찰 할 수있는 데이터 홀더 클래스입니다. 항상 최신 버전의 데이터를 보유 / 캐시합니다. 데이터가 변경되면 관찰자에게 알립니다. LiveData는 수명주기를 인식합니다. UI 구성 요소는 관련 데이터 만 관찰하며 관찰을 중지하거나 다시 시작하지 않습니다. LiveData는 관찰하는 동안 관련 수명주기 상태 변경을 인식하므로이 모든 것을 자동으로 관리합니다.


-2

SQLite 데이터베이스를 사용하여 세부 사항을 저장할 수 있습니다. 데이터에 쉽게 접근 할 수 있습니다. github에서 내 코드를 확인할 수 있습니다. https://github.com/thiru-wta/ToDo

     database = new Database(this);
    getSupportActionBar().setTitle("To Do List");
    etAddItems = (EditText) findViewById(R.id.etAddItem);
    btnAdd = (Button) findViewById(R.id.btnAdd);
    mRecyclerView = (RecyclerView) findViewById(R.id.listView);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    adapter = new RecyclerAdapter(this, listData);
    mRecyclerView.setAdapter(adapter);

    btnAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            event_name = etAddItems.getText().toString();
            String getname="";

              database.storeEventDetails(event_name);

                 getname = database.getEventDetails(event_name);


            if (getname.length() != 0) {
                listData.add(getname);
                etAddItems.setText("");

                adapter.notifyData(listData);
            }

데이터베이스 방법 :

    public void storeEventDetails(String event_name, long timerStart) {
    SQLiteDatabase db1 = getWritableDatabase();
    db1.execSQL("insert into '"+event_details_tbl+"' values('" + event_name + "')");
    db1.close();
}

방법을 얻으십시오 :

     public String getEventDetails(String event_name) {
    SQLiteDatabase db1 = getReadableDatabase();
    Cursor cur = db1.rawQuery("select * from '"+event_details_tbl+"' where     event_name ='" + event_name + "'", null);
    cur.moveToFirst();
    String evName = null;
    if (cur != null) {
        do {
            int eventName = cur.getColumnIndex("event_name");

            String ev_name = cur.getString(eventName);

            evName = ev_name;
        } while (cur.moveToNext());

    }
    cur.close();
    db1.close();
    return evName;

}     

-4

다음 단계를 수행하면됩니다.

  • recycler view.adapter에서 null 값으로 초기화 된 ArrayList 또는 Iterator를 작성하십시오.
  • 예를 들어 ex swapcursor와 같은 메소드를 작성하십시오 swapdata(Arraylist<T> data). 내부에서 배열 목록, 반복자 또는 시스템이 bindview에서 정수 위치를 사용하여 반복 할 수있는 모든 구조에 새로운 값을 제공합니다. 이 메소드의 값은에 전달됩니다 onloaderfinished(). 그런 다음 할당 직후에 전화하십시오 notifydatachange(). 이것들은 RecyclerView모든리스트를 새로운 ArrayList 데이터로 다시 그리 도록 요청할 것 입니다.

loadercalback을 사용중인 활동 또는 프래그먼트에서 어댑터에서 선택한 데이터 구조에 따라 커서를 배열 목록 또는 반복자로 변환하는 메소드를 작성하십시오.

이 방법으로 메인 스레드를 차단하지 않고 항상 loadercalback을 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.