परिचय
चूंकि यह आपके प्रश्न से वास्तव में स्पष्ट नहीं है कि वास्तव में आपको क्या परेशानी हो रही है, इसलिए मैंने इस सुविधा को कैसे लागू किया जाए, इस बारे में त्वरित रूप से लिखा; यदि आपके पास अभी भी प्रश्न पूछने के लिए स्वतंत्र हैं।
मेरे पास इस GitHub रिपॉजिटरी में जो कुछ भी मैं यहां बात कर रहा हूं उसका एक उदाहरण है ।
यदि आप उदाहरण प्रोजेक्ट के बारे में अधिक जानना चाहते हैं तो प्रोजेक्ट होमपेज पर जाएँ ।
किसी भी मामले में परिणाम कुछ इस तरह दिखना चाहिए:
यदि आप पहले डेमो ऐप के साथ खेलना चाहते हैं, तो आप इसे प्ले स्टोर से इंस्टॉल कर सकते हैं:
वैसे भी शुरू करने देता है।
की स्थापना SearchView
फ़ोल्डर में res/menu
नामक एक नई फ़ाइल बनाएँ main_menu.xml
। इसमें एक आइटम जोड़ें और actionViewClass
टू सेट करें android.support.v7.widget.SearchView
। चूंकि आप समर्थन लाइब्रेरी का उपयोग कर रहे हैं, इसलिए आपको actionViewClass
विशेषता सेट करने के लिए समर्थन लाइब्रेरी के नामस्थान का उपयोग करना होगा । आपकी xml फ़ाइल कुछ इस तरह दिखनी चाहिए:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="@string/action_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"/>
</menu>
आपके Fragment
या Activity
आपको सामान्य रूप से इस मेनू xml को बढ़ाना है, तो आप इसके लिए देख सकते हैं MenuItem
जिसमें शामिल है SearchView
और OnQueryTextListener
जिसे हम पाठ में दर्ज किए गए परिवर्तनों को सुनने के लिए उपयोग करने जा रहे हैं SearchView
:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
@Override
public boolean onQueryTextChange(String query) {
// Here is where we are going to implement the filter logic
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
और अब SearchView
उपयोग करने के लिए तैयार है। हम फ़िल्टर लॉजिक को बाद में लागू कर देंगे onQueryTextChange()
जब हम समाप्त कर देंगे Adapter
।
की स्थापना Adapter
सबसे पहला और महत्वपूर्ण यह है कि मैं इस उदाहरण के लिए जिस मॉडल वर्ग का उपयोग करने जा रहा हूं:
public class ExampleModel {
private final long mId;
private final String mText;
public ExampleModel(long id, String text) {
mId = id;
mText = text;
}
public long getId() {
return mId;
}
public String getText() {
return mText;
}
}
यह सिर्फ अपने बुनियादी मॉडल है जिसमें एक पाठ प्रदर्शित करेगा है RecyclerView
। यह वह लेआउट है जिसे मैं टेक्स्ट प्रदर्शित करने के लिए उपयोग करने जा रहा हूं:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="model"
type="com.github.wrdlbrnft.searchablerecyclerviewdemo.ui.models.ExampleModel"/>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="@{model.text}"/>
</FrameLayout>
</layout>
जैसा कि आप देख सकते हैं कि मैं डेटा बाइंडिंग का उपयोग करता हूं। यदि आपने कभी छूटने से पहले डेटा बाइंडिंग के साथ काम नहीं किया है! यह बहुत सरल और शक्तिशाली है, हालांकि मैं यह नहीं बता सकता कि यह इस उत्तर के दायरे में कैसे काम करता है।
यह वह जगह है ViewHolder
के लिए ExampleModel
वर्ग:
public class ExampleViewHolder extends RecyclerView.ViewHolder {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
public void bind(ExampleModel item) {
mBinding.setModel(item);
}
}
फिर कुछ खास नहीं। यह सिर्फ इस लेआउट में मॉडल वर्ग को बांधने के लिए डेटा बाइंडिंग का उपयोग करता है जैसा कि हमने ऊपर के लेआउट xml में परिभाषित किया है।
अब हम अंततः वास्तव में दिलचस्प हिस्से पर आ सकते हैं: एडेप्टर लिखना। मैं Adapter
इसके जवाब के लिए प्रासंगिक भागों पर ध्यान केंद्रित करने जा रहा हूं और इसके मूल कार्यान्वयन को छोड़ रहा हूं ।
लेकिन पहले एक बात है जो हमें करनी है: SortedList
कक्षा।
SortedList
SortedList
जो का हिस्सा है एक पूरी तरह से अद्भुत उपकरण है RecyclerView
पुस्तकालय। यह Adapter
डेटा सेट के परिवर्तनों के बारे में सूचित करने का ध्यान रखता है और इसलिए यह एक बहुत ही कुशल तरीका है। केवल एक चीज जो आपको करने की आवश्यकता है वह तत्वों के एक आदेश को निर्दिष्ट करना है। आपको एक ऐसा compare()
तरीका लागू करने की आवश्यकता है जो दो तत्वों की तुलना करता है SortedList
जैसे कि ए Comparator
। लेकिन छँटाई के बजाय List
इसका उपयोग वस्तुओं को क्रमबद्ध करने के लिए किया जाता है RecyclerView
!
SortedList
साथ सूचना का आदान Adapter
एक के माध्यम से Callback
वर्ग है जो आप को लागू करने के लिए है:
private final SortedList.Callback<ExampleModel> mCallback = new SortedList.Callback<ExampleModel>() {
@Override
public void onInserted(int position, int count) {
mAdapter.notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
mAdapter.notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
mAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
mAdapter.notifyItemRangeChanged(position, count);
}
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
}
जैसे कॉलबैक के शीर्ष पर तरीकों में onMoved
, onInserted
आदि आप कॉल करने के लिए बराबर सूचित अपने की विधि है Adapter
। तल पर तीन विधियाँ compare
, areContentsTheSame
और areItemsTheSame
आपको यह प्रदर्शित करना होगा कि आप किस प्रकार की वस्तुओं को प्रदर्शित करना चाहते हैं और किस क्रम में इन वस्तुओं को स्क्रीन पर दिखाना चाहिए।
आइए इन तरीकों को एक-एक करके देखें:
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
यह वह compare()
विधि है जिसके बारे में मैंने पहले बात की थी। इस उदाहरण में मैं केवल Comparator
दो मॉडलों की तुलना करने के लिए कॉल पास कर रहा हूं । यदि आप चाहते हैं कि आइटम स्क्रीन पर वर्णानुक्रम में दिखाई दें। यह तुलनित्र इस तरह दिख सकता है:
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
अब अगली विधि पर एक नज़र डालते हैं:
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
इस पद्धति का उद्देश्य यह निर्धारित करना है कि क्या किसी मॉडल की सामग्री बदल गई है। यह SortedList
निर्धारित करने के लिए इसका उपयोग करता है कि क्या परिवर्तन घटना को लागू करने की आवश्यकता है - दूसरे शब्दों में अगर RecyclerView
पुराने और नए संस्करण को पार करना चाहिए। यदि आपके पास मॉडल कक्षाएं सही equals()
और hashCode()
कार्यान्वयन हैं, तो आप आमतौर पर इसे ऊपर की तरह लागू कर सकते हैं। यदि हम कक्षा में एक equals()
और hashCode()
कार्यान्वयन जोड़ते हैं तो ExampleModel
इसे कुछ इस तरह देखना चाहिए:
public class ExampleModel implements SortedListAdapter.ViewModel {
private final long mId;
private final String mText;
public ExampleModel(long id, String text) {
mId = id;
mText = text;
}
public long getId() {
return mId;
}
public String getText() {
return mText;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExampleModel model = (ExampleModel) o;
if (mId != model.mId) return false;
return mText != null ? mText.equals(model.mText) : model.mText == null;
}
@Override
public int hashCode() {
int result = (int) (mId ^ (mId >>> 32));
result = 31 * result + (mText != null ? mText.hashCode() : 0);
return result;
}
}
त्वरित पक्ष नोट: अधिकांश IDE जैसे Android Studio, IntelliJ और Eclipse में एक बटन के प्रेस पर आपके लिए जेनरेट equals()
और hashCode()
कार्यान्वयन की कार्यक्षमता है ! इसलिए आपको उन्हें स्वयं लागू करने की आवश्यकता नहीं है। इंटरनेट पर देखें कि यह आपके IDE में कैसे काम करता है!
अब आइए एक नजर डालते हैं आखिरी विधि पर:
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
यह SortedList
जाँचने के लिए कि दो आइटम एक ही चीज़ को संदर्भित करते हैं, इस विधि का उपयोग करता है। सबसे सरल शब्दों में (यह बताए बिना कि यह कैसे SortedList
काम करता है) यह निर्धारित करने के लिए उपयोग किया जाता है कि क्या कोई वस्तु पहले से ही मौजूद है List
और यदि ऐड, मूव या चेंज एनीमेशन को प्ले करने की आवश्यकता है। यदि आपके मॉडलों में एक आईडी है तो आप आमतौर पर इस विधि में केवल आईडी की तुलना करेंगे। यदि उन्हें इसकी जांच करने के लिए किसी अन्य तरीके का पता लगाने की आवश्यकता नहीं है, लेकिन फिर भी आप इसे लागू करते हैं, यह आपके विशिष्ट ऐप पर निर्भर करता है। आमतौर पर सभी मॉडलों को एक आईडी देना सबसे सरल विकल्प है - उदाहरण के लिए प्राथमिक कुंजी क्षेत्र हो सकता है यदि आप किसी डेटाबेस से डेटा क्वेरी कर रहे हैं।
SortedList.Callback
सही तरीके से लागू किए जाने के साथ हम निम्न का एक उदाहरण बना सकते हैं SortedList
:
final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);
आप के निर्माता में पहले पैरामीटर के रूप SortedList
में अपने मॉडल के वर्ग को पास करने की आवश्यकता है। अन्य पैरामीटर बस SortedList.Callback
हम ऊपर परिभाषित है।
अगर हम लागू: अब के व्यापार करने के लिए नीचे जाओ Adapter
एक साथ SortedList
यह कुछ इस तरह दिखना चाहिए:
public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {
private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
});
private final LayoutInflater mInflater;
private final Comparator<ExampleModel> mComparator;
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
mInflater = LayoutInflater.from(context);
mComparator = comparator;
}
@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
final ExampleModel model = mSortedList.get(position);
holder.bind(model);
}
@Override
public int getItemCount() {
return mSortedList.size();
}
}
Comparator
सॉर्ट करने के लिए तो हम एक ही उपयोग कर सकते हैं आइटम निर्माता के माध्यम से में पारित हो जाता है के लिए इस्तेमाल किया Adapter
भी आइटम भिन्न क्रम में प्रदर्शित करने के लिए की अपेक्षा की जाती है।
अब हम लगभग हो चुके हैं! लेकिन हमें सबसे पहले वस्तुओं को जोड़ने या हटाने का तरीका चाहिए Adapter
। इस उद्देश्य के लिए हम उन विधियों को जोड़ सकते हैं Adapter
जिनसे हमें आइटम जोड़ने और हटाने की अनुमति मिलती है SortedList
:
public void add(ExampleModel model) {
mSortedList.add(model);
}
public void remove(ExampleModel model) {
mSortedList.remove(model);
}
public void add(List<ExampleModel> models) {
mSortedList.addAll(models);
}
public void remove(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (ExampleModel model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
हमें यहां किसी भी अधिसूचित तरीके को कॉल करने की आवश्यकता नहीं है क्योंकि SortedList
पहले से ही इसके माध्यम से किया जाता है SortedList.Callback
! इसके अलावा, इन विधियों का कार्यान्वयन एक अपवाद के साथ बहुत सीधा है: हटाने का तरीका जो एक List
मॉडल को निकालता है । चूंकि SortedList
केवल एक हटाने की विधि है जो एक एकल ऑब्जेक्ट को हटा सकती है जिसे हमें सूची पर लूप करने की आवश्यकता है और एक-एक करके मॉडल को हटा दें। beginBatchedUpdates()
शुरुआत में कॉल करना उन सभी परिवर्तनों को दर्शाता है जो हम SortedList
एक साथ करने जा रहे हैं और प्रदर्शन में सुधार करते हैं। जब हम कॉल endBatchedUpdates()
करते हैं RecyclerView
तो एक ही बार में सभी परिवर्तनों के बारे में सूचित किया जाता है।
इसके अतिरिक्त आपको जो समझना है, वह यह है कि यदि आप इसमें कोई ऑब्जेक्ट जोड़ते हैं SortedList
और यह पहले से ही है तो SortedList
इसे दोबारा नहीं जोड़ा जाएगा। इसके बजाय विधि SortedList
का उपयोग करता है यह areContentsTheSame()
पता लगाने के लिए कि क्या वस्तु बदल गई है - और यदि इसमें RecyclerView
वसीयत में आइटम अपडेट है।
वैसे भी, जो मैं आमतौर पर पसंद करता हूं वह एक तरीका है जो मुझे RecyclerView
एक ही बार में सभी वस्तुओं को बदलने की अनुमति देता है । जो कुछ भी नहीं है उसे निकालें List
और उन सभी वस्तुओं को जोड़ें जो गायब हैं SortedList
:
public void replaceAll(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() - 1; i >= 0; i--) {
final ExampleModel model = mSortedList.get(i);
if (!models.contains(model)) {
mSortedList.remove(model);
}
}
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
यह विधि फिर से प्रदर्शन को बढ़ाने के लिए सभी अपडेट को एक साथ बैचती है। पहला लूप उल्टा है क्योंकि शुरू में एक आइटम को हटाने से उसके बाद आने वाली सभी वस्तुओं के सूचकांक में गड़बड़ हो जाती है और इससे डेटा असंगति जैसी समस्याओं के कुछ उदाहरण हो सकते हैं। उसके बाद हम केवल उन सभी वस्तुओं को जोड़ने के List
लिए SortedList
उपयोग addAll()
करने के लिए जोड़ते हैं जो पहले से ही नहीं हैं SortedList
और - जैसे मैंने ऊपर वर्णित किया है - उन सभी वस्तुओं को अपडेट करें जो पहले से ही SortedList
बदल चुके हैं लेकिन बदल गए हैं।
और इसके साथ Adapter
ही पूरा हो गया है। पूरी बात कुछ इस तरह दिखनी चाहिए:
public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {
private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1 == item2;
}
});
private final Comparator<ExampleModel> mComparator;
private final LayoutInflater mInflater;
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
mInflater = LayoutInflater.from(context);
mComparator = comparator;
}
@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(mInflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
final ExampleModel model = mSortedList.get(position);
holder.bind(model);
}
public void add(ExampleModel model) {
mSortedList.add(model);
}
public void remove(ExampleModel model) {
mSortedList.remove(model);
}
public void add(List<ExampleModel> models) {
mSortedList.addAll(models);
}
public void remove(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (ExampleModel model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
public void replaceAll(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() - 1; i >= 0; i--) {
final ExampleModel model = mSortedList.get(i);
if (!models.contains(model)) {
mSortedList.remove(model);
}
}
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
@Override
public int getItemCount() {
return mSortedList.size();
}
}
फ़िल्टरिंग को लागू करने के लिए अब केवल एक चीज गायब है!
फ़िल्टर तर्क को लागू करना
फ़िल्टर तर्क को लागू करने के लिए हमें सबसे पहले List
सभी संभावित मॉडल को परिभाषित करना होगा । इस उदाहरण के लिए मैं एक बनाने List
की ExampleModel
फिल्मों की एक सरणी से उदाहरणों:
private static final String[] MOVIES = new String[]{
...
};
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
private ExampleAdapter mAdapter;
private List<ExampleModel> mModels;
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mAdapter = new ExampleAdapter(this, ALPHABETICAL_COMPARATOR);
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mBinding.recyclerView.setAdapter(mAdapter);
mModels = new ArrayList<>();
for (String movie : MOVIES) {
mModels.add(new ExampleModel(movie));
}
mAdapter.add(mModels);
}
यहां कुछ खास नहीं चल रहा है, हम बस Adapter
इसे इंस्टेंट करते हैं और इसे सेट करते हैं RecyclerView
। उसके बाद हम ऐरे List
में मूवी के नामों से मॉडल बनाते हैं MOVIES
। फिर हम सभी मॉडलों को मॉडल में जोड़ते हैं SortedList
।
अब हम वापस जा सकते हैं, onQueryTextChange()
जिसे हमने पहले परिभाषित किया था और फ़िल्टर तर्क को लागू करना शुरू किया था:
@Override
public boolean onQueryTextChange(String query) {
final List<ExampleModel> filteredModelList = filter(mModels, query);
mAdapter.replaceAll(filteredModelList);
mBinding.recyclerView.scrollToPosition(0);
return true;
}
यह फिर से बहुत सीधे आगे है। हम विधि कॉल filter()
और पास List
के ExampleModel
साथ ही क्वेरी स्ट्रिंग के रूप में। फिर हम कॉल replaceAll()
करते हैं Adapter
और फ़िल्टर किए List
गए में पास करते हैं filter()
। हम यह भी कॉल कर सकते हैं scrollToPosition(0)
पर RecyclerView
यह सुनिश्चित करें कि उपयोगकर्ता हमेशा सभी आइटम देख सकते हैं जब किसी चीज़ को खोजने। अन्यथा RecyclerView
फ़िल्टर करते समय नीचे स्क्रॉल की गई स्थिति में रह सकते हैं और बाद में कुछ आइटम छिपा सकते हैं। खोज करते समय शीर्ष पर स्क्रॉल करना बेहतर उपयोगकर्ता अनुभव सुनिश्चित करता है।
अब केवल एक ही चीज शेष filter()
है:
private static List<ExampleModel> filter(List<ExampleModel> models, String query) {
final String lowerCaseQuery = query.toLowerCase();
final List<ExampleModel> filteredModelList = new ArrayList<>();
for (ExampleModel model : models) {
final String text = model.getText().toLowerCase();
if (text.contains(lowerCaseQuery)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
पहली चीज जो हम यहां करते हैं वह toLowerCase()
क्वेरी स्ट्रिंग पर कॉल है । हम नहीं चाहते हैं कि हमारा खोज कार्य संवेदनशील हो और toLowerCase()
हम सभी तुलनाओं पर कॉल करके यह सुनिश्चित कर सकें कि हम मामले की परवाह किए बिना समान परिणाम लौटा सकें। यह तब होता है जब List
हम इसमें पारित सभी मॉडलों के माध्यम से पुनरावृत्त होते हैं और यह जांचते हैं कि क्या क्वेरी स्ट्रिंग मॉडल के पाठ में निहित है। यदि यह है तो मॉडल को फ़िल्टर्ड में जोड़ा जाता है List
।
और बस! उपरोक्त कोड एपीआई स्तर 7 और इसके बाद के संस्करण पर चलेंगे और एपीआई स्तर 11 से शुरू होकर आपको मुफ्त में आइटम एनिमेशन मिलेंगे!
मुझे पता है कि यह एक बहुत ही विस्तृत विवरण है जो संभवतः इस पूरी चीज़ को वास्तव में की तुलना में अधिक जटिल लगता है, लेकिन एक तरीका है जिससे हम इस पूरी समस्या का सामान्यीकरण कर सकते हैं और बहुत सरलता के Adapter
आधार पर इसे लागू कर सकते हैं SortedList
।
समस्या को सामान्य करना और एडेप्टर को सरल बनाना
इस खंड में मैं बहुत विस्तार में नहीं जा रहा हूं - आंशिक रूप से क्योंकि मैं स्टैक ओवरफ्लो पर जवाब के लिए वर्ण सीमा के खिलाफ चल रहा हूं, लेकिन यह भी क्योंकि इसमें से अधिकांश पहले ही ऊपर बताए गए हैं - लेकिन परिवर्तनों को संक्षेप में बताने के लिए: हम एक बेस Adapter
क्लास लागू कर सकते हैं जो पहले से ही उदाहरणों के SortedList
साथ-साथ बाध्यकारी मॉडल से निपटने का ख्याल रखता है ViewHolder
और एक के Adapter
आधार पर लागू करने के लिए एक सुविधाजनक तरीका प्रदान करता हैSortedList
। उसके लिए हमें दो काम करने होंगे:
- हमें एक बनाने की जरूरत है
ViewModel
इंटरफ़ेस जिसे सभी मॉडल वर्गों को लागू करना होगा
- हमें एक
ViewHolder
उपवर्ग बनाने की आवश्यकता है जो एक bind()
विधि को परिभाषित करता है जो Adapter
मॉडल को स्वचालित रूप से बांधने के लिए उपयोग कर सकता है।
यह हमें केवल उस सामग्री पर ध्यान केंद्रित करने की अनुमति देता है RecyclerView
जिसे केवल मॉडलों को लागू करने के द्वारा प्रदर्शित किया जाता है और इसके अनुरूप ViewHolder
कार्यान्वयन होता है। इस बेस क्लास का उपयोग करके हमें Adapter
इसके और इसके जटिल विवरण के बारे में चिंता करने की आवश्यकता नहीं है SortedList
।
SortedListAdapter
StackOverflow पर उत्तरों की वर्ण सीमा के कारण मैं इस बेस क्लास को लागू करने के प्रत्येक चरण के माध्यम से नहीं जा सकता या यहाँ पूर्ण स्रोत कोड भी जोड़ सकता हूँ, लेकिन आप इस बेस क्लास का पूर्ण स्रोत कोड पा सकते हैं - मैंने इसे कॉल किया SortedListAdapter
- इसमें गिटहब गिस्ट ।
आपके जीवन को सरल बनाने के लिए मैंने jCenter पर एक पुस्तकालय प्रकाशित किया है जिसमें सम्मिलित है SortedListAdapter
! यदि आप इसका उपयोग करना चाहते हैं तो आपको बस इतना करना है कि इस निर्भरता को अपने ऐप की बिल्ड.ग्रेड फ़ाइल में जोड़ें:
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.1'
आप इस पुस्तकालय के बारे में अधिक जानकारी पुस्तकालय के मुखपृष्ठ पर पा सकते हैं ।
SortedListAdapter का उपयोग करना
उपयोग करने के लिए SortedListAdapter
हमें दो बदलाव करने होंगे:
बदलो ViewHolder
ताकि यह विस्तारित हो SortedListAdapter.ViewHolder
। प्रकार का पैरामीटर मॉडल होना चाहिए जो ViewHolder
इस मामले में बाध्य होना चाहिए - इस मामले में ExampleModel
। आपको performBind()
इसके बजाय अपने मॉडल में डेटा को बांधना होगा bind()
।
public class ExampleViewHolder extends SortedListAdapter.ViewHolder<ExampleModel> {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
@Override
protected void performBind(ExampleModel item) {
mBinding.setModel(item);
}
}
सुनिश्चित करें कि आपके सभी मॉडल ViewModel
इंटरफ़ेस को लागू करते हैं :
public class ExampleModel implements SortedListAdapter.ViewModel {
...
}
उसके बाद हमें केवल उन चीजों ExampleAdapter
को बढ़ाने SortedListAdapter
और हटाने के लिए अपडेट करना होगा जिनकी हमें अब आवश्यकता नहीं है। प्रकार पैरामीटर उस मॉडल का प्रकार होना चाहिए जिसके साथ आप काम कर रहे हैं - इस मामले में ExampleModel
। लेकिन अगर आप विभिन्न प्रकार के मॉडल के साथ काम कर रहे हैं तो टाइप पैरामीटर को सेट करें ViewModel
।
public class ExampleAdapter extends SortedListAdapter<ExampleModel> {
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
super(context, ExampleModel.class, comparator);
}
@Override
protected ViewHolder<? extends ExampleModel> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
protected boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
@Override
protected boolean areItemContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
}
उसके बाद हम कर रहे हैं! हालाँकि एक अंतिम बात जो उल्लेखित है: हमारे मूल SortedListAdapter
में वही add()
, remove()
या replaceAll()
विधियाँ नहीं हैं ExampleAdapter
। यह Editor
सूची में आइटम को संशोधित करने के लिए एक अलग ऑब्जेक्ट का उपयोग करता है जिसे edit()
विधि के माध्यम से एक्सेस किया जा सकता है । इसलिए यदि आप उन वस्तुओं को हटाना या जोड़ना चाहते हैं जिन्हें आपको कॉल करना है, edit()
तो इस Editor
उदाहरण पर आइटम जोड़ें और निकालें और एक बार जब आप कर लें, तो इस commit()
पर कॉल करें SortedList
: परिवर्तन लागू करने के लिए :
mAdapter.edit()
.remove(modelToRemove)
.add(listOfModelsToAdd)
.commit();
इस तरह से किए जाने वाले सभी परिवर्तनों को प्रदर्शन बढ़ाने के लिए एक साथ बैच दिया जाता है। replaceAll()
ऊपर दिए गए अध्यायों में हमने जो विधि लागू की है वह इस Editor
वस्तु पर भी मौजूद है :
mAdapter.edit()
.replaceAll(mModels)
.commit();
अगर आप कॉल करना भूल जाते हैं commit()
तो आपका कोई भी बदलाव लागू नहीं होगा!