কীভাবে একটি অনুসন্ধানের সাথে একটি পুনর্ব্যবহারযোগ্য ফিল্টার করতে হয়


319

আমি SearchViewসমর্থন লাইব্রেরি থেকে প্রয়োগ করার চেষ্টা করছি । আমি চাই যে ব্যবহারকারীরা SearchViewএকটিতে Listচলচ্চিত্রের একটি ফিল্টার করতে ব্যবহার করুন RecyclerView

আমি এতদূর কয়েক টিউটোরিয়াল অনুসরণ করেছেন এবং আমি যোগ করেছি SearchViewকরতে ActionBar, কিন্তু আমি সত্যিই নিশ্চিত যেখানে এখানে থেকে যান নই। আমি কয়েকটি উদাহরণ দেখেছি কিন্তু আপনি টাইপ করা শুরু করার সাথে এর মধ্যে কোনও ফলাফল দেখায় না।

এটি আমার MainActivity:

public class MainActivity extends ActionBarActivity {

    RecyclerView mRecyclerView;
    RecyclerView.LayoutManager mLayoutManager;
    RecyclerView.Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mAdapter = new CardAdapter() {
            @Override
            public Filter getFilter() {
                return null;
            }
        };
        mRecyclerView.setAdapter(mAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

এবং এটি আমার Adapter:

public abstract class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> implements Filterable {

    List<Movie> mItems;

    public CardAdapter() {
        super();
        mItems = new ArrayList<Movie>();
        Movie movie = new Movie();
        movie.setName("Spiderman");
        movie.setRating("92");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Doom 3");
        movie.setRating("91");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers");
        movie.setRating("88");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers 2");
        movie.setRating("87");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers 3");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Noah");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman 2");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman 3");
        movie.setRating("86");
        mItems.add(movie);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_card_item, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Movie movie = mItems.get(i);
        viewHolder.tvMovie.setText(movie.getName());
        viewHolder.tvMovieRating.setText(movie.getRating());
    }

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

    class ViewHolder extends RecyclerView.ViewHolder{

        public TextView tvMovie;
        public TextView tvMovieRating;

        public ViewHolder(View itemView) {
            super(itemView);
            tvMovie = (TextView)itemView.findViewById(R.id.movieName);
            tvMovieRating = (TextView)itemView.findViewById(R.id.movieRating);
        }
    }
}

উত্তর:


913

ভূমিকা

যেহেতু আপনি ঠিক কী সমস্যায় পড়েছেন তা আপনার প্রশ্ন থেকে সত্যই স্পষ্ট নয়, এই বৈশিষ্ট্যটি কীভাবে বাস্তবায়ন করা যায় সে সম্পর্কে আমি এই দ্রুত পদক্ষেপটি লিখেছিলাম; আপনার যদি এখনও প্রশ্ন থাকে তবে নির্দ্বিধায় জিজ্ঞাসা করুন।

আমি এখানে এই গিটহব রেপোজিটরিতে যা বলছি তার প্রতিটি কাজের উদাহরণ রয়েছে ।
আপনি উদাহরণস্বরূপ প্রকল্প সম্পর্কে আরও জানতে চাইলে প্রকল্পের হোমপেজটি দেখুন

যে কোনও ক্ষেত্রে ফলাফলটি দেখতে এরকম কিছু হওয়া উচিত:

ডেমো ইমেজ

আপনি যদি প্রথমে ডেমো অ্যাপ্লিকেশনটির সাথে খেলতে চান তবে আপনি এটি প্লে স্টোর থেকে ইনস্টল করতে পারেন:

এটা গুগল প্লে তে পাবেন

যাইহোক শুরু করা যাক।


সেট আপ করা হচ্ছে SearchView

ফোল্ডারে কল করা res/menuএকটি নতুন ফাইল তৈরি করুন main_menu.xml। এটা এ একটি আইটেম যোগ করতে পারেন এবং সেট actionViewClassকরার android.support.v7.widget.SearchView। যেহেতু আপনি সমর্থন লাইব্রেরি ব্যবহার করছেন আপনাকে actionViewClassবৈশিষ্ট্যটি সেট করতে সমর্থন লাইব্রেরির নাম স্থানটি ব্যবহার করতে হবে । আপনার এক্সএমএল ফাইলটি দেখতে এমন কিছু হওয়া উচিত:

<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আপনাকে যথারীতি এই মেনুতে এক্সএমএল স্ফীত করতে হবে, তারপরে আপনি 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;
    }
}

দ্রুত দিক নোট: বেশিরভাগ আইডিই এর মতো অ্যান্ড্রয়েড স্টুডিও, ইন্টেলিজিজ এবং ইক্লিপস তৈরির কার্যকারিতা রয়েছে equals() এবং hashCode()একটি বোতামের টিপে আপনার জন্য বাস্তবায়ন! সুতরাং এগুলি আপনাকে নিজে প্রয়োগ করতে হবে না। আপনার আইডিইতে এটি কীভাবে কাজ করে তা ইন্টারনেটে সন্ধান করুন!

এবার আসুন শেষ পদ্ধতিটি একবার দেখুন:

@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
    return item1.getId() == item2.getId();
}

দ্য SortedListযদি দুটি আইটেম একই জিনিস পড়ুন পরীক্ষা এই পদ্ধতি ব্যবহার করে। সরল কথায় (এটি কীভাবে SortedListকাজ করে তা ব্যাখ্যা না করে) এটি নির্ধারণ করতে ব্যবহৃত হয় যে কোনও বস্তু ইতিমধ্যে অন্তর্ভুক্ত রয়েছে Listএবং যদি কোনও অ্যাড, মুভ বা পরিবর্তন অ্যানিমেশন চালানো দরকার needs আপনার মডেলগুলির কোনও আইডি থাকলে আপনি সাধারণত এই পদ্ধতিতে কেবল আইডি তুলনা করতে পারেন। এগুলি পরীক্ষা করার জন্য যদি আপনার অন্য কোনও উপায়ে বের করার প্রয়োজন হয় না তবে তবে আপনি এটি প্রয়োগ করে শেষ করেন আপনার নির্দিষ্ট অ্যাপের উপর। সাধারণত সমস্ত মডেলকে একটি আইডি দেওয়ার সহজ বিকল্প - এটি উদাহরণস্বরূপ প্রাথমিক কী ক্ষেত্র হতে পারে যদি আপনি কোনও ডাটাবেস থেকে ডেটা জিজ্ঞাসা করেন।

সঙ্গে 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এটিতে যুক্ত হয় না be পরিবর্তে এই পদ্ধতিটি 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();
}

এই পদ্ধতিটি আবার সমস্ত আপডেট একসাথে পারফরম্যান্স বাড়ায় ches প্রথম লুপটি বিপরীত যেহেতু শুরুতে কোনও আইটেম সরিয়ে ফেললে তার পরে আসা সমস্ত আইটেমের সূচিগুলিকে গোলমাল করে দেয় এবং এটি ডেটা অসঙ্গতির মতো সমস্যার কারণ হতে পারে। এরপর আমরা শুধু যোগ 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এবং পাস করি । কোনও কিছুর সন্ধান করার সময় ব্যবহারকারী সর্বদা সমস্ত আইটেম দেখতে পারে তা নিশ্চিত করার জন্য আমাদেরও কল করতে হবে। অন্যথায় ফিল্টার করার সময় সম্ভবত স্ক্রলড ডাউন অবস্থায় থাকতে পারে এবং পরে কয়েকটি আইটেম লুকিয়ে রাখতে পারে। শীর্ষে স্ক্রোলিং অনুসন্ধানের সময় আরও ভাল ব্যবহারকারীর অভিজ্ঞতা নিশ্চিত করে।Listfilter()scrollToPosition(0)RecyclerViewRecyclerView

এখনই কেবল নিজের কাজটি বাস্তবায়ন 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

স্ট্যাকওভারফ্লোতে উত্তরের চরিত্রের সীমাবদ্ধতার কারণে আমি এই বেস শ্রেণিটি বাস্তবায়নের প্রতিটি পদক্ষেপের মধ্য দিয়ে যেতে পারি না এমনকি এখানে পুরো উত্স কোড যুক্ত করতে পারি না, তবে আপনি এই বেস শ্রেণীর পুরো উত্স কোডটি খুঁজে পেতে পারেন - আমি এটি বলেছি SortedListAdapter- এটিতে গিটহাব গিস্ট

আপনার জীবনকে সহজ করতে আমি jCenter এ একটি লাইব্রেরি প্রকাশ করেছি যা এতে রয়েছে SortedListAdapter! আপনি যদি এটি ব্যবহার করতে চান তবে আপনাকে যা করতে হবে তা হ'ল আপনার অ্যাপ্লিকেশনটির বিল্ড.gradle ফাইলটিতে এই নির্ভরতা যুক্ত করুন:

compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.1'

আপনি লাইব্রেরির হোমপেজে এই লাইব্রেরি সম্পর্কে আরও তথ্য পেতে পারেন

সাজানোলিস্টএডাপ্টার ব্যবহার করে

ব্যবহার SortedListAdapterকরতে আমাদের দুটি পরিবর্তন করতে হবে:

  • পরিবর্তন করুন ViewHolderযাতে এটি প্রসারিত হয় SortedListAdapter.ViewHolder। প্রকারের পরামিতিটি এমন মডেল হওয়া উচিত যা এটির সাথে আবদ্ধ হওয়া উচিত ViewHolder- এই ক্ষেত্রে ExampleModelperformBind()পরিবর্তে আপনাকে আপনার মডেলগুলিতে ডেটা বাঁধতে হবে 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()তবে আপনার কোনও পরিবর্তনই প্রয়োগ করা হবে না!


4
@ টিয়াগো অলিভেরা ঠিক আছে এটি কেবল বাক্সের বাইরে কাজ করার জন্য তৈরি করা হয়েছে: ডি ডাটা বাইন্ডিং এটির সাথে অপরিচিত লোকদের পক্ষে বাধা, তবে আমি এটিকে যাইহোক অন্তর্ভুক্ত করেছি কারণ এটি আশ্চর্যজনক এবং আমি এটি প্রচার করতে চাই। কোনও কারণে এটির পক্ষে অনেকেই জানেন না বলে মনে হয় ...
জাভার কাপেলার

78
আমি এখনও পুরো উত্তরটি পড়িনি, এই মন্তব্যটি লেখার জন্য আমার পড়াটি অর্ধেকের দিকে বিরতিতে হয়েছিল - এটি এসও-তে এখানে পাওয়া সেরা উত্তরগুলির মধ্যে একটি! ধন্যবাদ!
দানিজেলা

16
আমি কেবল আপনার পছন্দটি পছন্দ করি: "আপনার কী সমস্যা হচ্ছে তা আপনার প্রশ্ন থেকে পরিষ্কার নয়, সুতরাং আমি এখানে একটি সম্পূর্ণ উদাহরণ দিয়েছি": ডি
ফ্রেড

7
+1 কেবলমাত্র আমাদের দেখানোর জন্য যে অ্যান্ড্রয়েডে ডেটা বাঁধাই রয়েছে আমি এটি সম্পর্কে কখনও শুনিনি এবং মনে হয় আমি এটি ব্যবহার শুরু করব। ধন্যবাদ
জর্জি ক্যাসেরিগো

6
এই সমাধানটি হাস্যকরভাবে দীর্ঘ এবং সাধারণত ওভার ইঞ্জিনিয়ারযুক্ত speaking দ্বিতীয়টির জন্য যান।
এনরিকো ক্যাসিনি

194

আপনাকে যা করতে হবে তা হ'ল filterপদ্ধতিতে যুক্ত করা RecyclerView.Adapter:

public void filter(String text) {
    items.clear();
    if(text.isEmpty()){
        items.addAll(itemsCopy);
    } else{
        text = text.toLowerCase();
        for(PhoneBookItem item: itemsCopy){
            if(item.name.toLowerCase().contains(text) || item.phone.toLowerCase().contains(text)){
                items.add(item);
            }
        }
    }
    notifyDataSetChanged();
}

itemsCopy অ্যাডাপ্টারের কনস্ট্রাক্টরের মতো ইনিশিয়াল করা হয় itemsCopy.addAll(items)

যদি আপনি এটি করেন তবে কেবল filterএখান থেকে কল করুন OnQueryTextListener:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        adapter.filter(query);
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        adapter.filter(newText);
        return true;
    }
});

নাম এবং ফোন নম্বর দ্বারা আমার ফোনবুক ফিল্টার করা এটির একটি উদাহরণ।


11
আমি মনে করি এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। এটি সহজ এবং এটি কেবল কাজ করে
জোসে_জিডি

6
সহজ এবং দক্ষ!
অ্যালেক্সড্রয়েডদেভ

11
মনে রাখবেন যে আপনি যদি @ জাভার ক্যাপেলারের উত্তরের পরিবর্তে এই পদ্ধতির অনুসরণ করেন তবে অ্যানিমেশনটি হারাবেন।
২৪

23
গৃহীত উত্তরটি চেষ্টা করে দেখেনি কারণ এটি অনেক দীর্ঘ। এই উত্তর কার্যকর এবং কার্যকর করা সহজ। আপনার মেনু আইটেম এক্সএমএলে "অ্যাপ: অ্যাকশনভিউক্লাস =" android.support.v7.widget.S SearchView "যুক্ত করতে ভুলবেন না।
সাজিতক

3
ঠিক এখানে আইটেম এবং আইটেম কপি কি?
ভাগ্যবান_গর্

82

একটি পরিষ্কার উপায়ে @ শ্রুতি কামোজি অনুসরণ করে, আমরা কেবল একটি ফিল্টারযোগ্য ব্যবহার করতে পারি, এর জন্য এটি বোঝানো হয়েছে:

public abstract class GenericRecycleAdapter<E> extends RecyclerView.Adapter implements Filterable
{
    protected List<E> list;
    protected List<E> originalList;
    protected Context context;

    public GenericRecycleAdapter(Context context,
    List<E> list)
    {
        this.originalList = list;
        this.list = list;
        this.context = context;
    }

    ...

    @Override
    public Filter getFilter() {
        return new Filter() {
            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                list = (List<E>) results.values;
                notifyDataSetChanged();
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                List<E> filteredResults = null;
                if (constraint.length() == 0) {
                    filteredResults = originalList;
                } else {
                    filteredResults = getFilteredResults(constraint.toString().toLowerCase());
                }

                FilterResults results = new FilterResults();
                results.values = filteredResults;

                return results;
            }
        };
    }

    protected List<E> getFilteredResults(String constraint) {
        List<E> results = new ArrayList<>();

        for (E item : originalList) {
            if (item.getName().toLowerCase().contains(constraint)) {
                results.add(item);
            }
        }
        return results;
    }
} 

E এখানে একটি জেনেরিক প্রকার, আপনি এটি আপনার শ্রেণি ব্যবহার করে প্রসারিত করতে পারেন:

public class customerAdapter extends GenericRecycleAdapter<CustomerModel>

অথবা কেবল ইটি আপনার পছন্দ মতো পরিবর্তন করুন ( <CustomerModel>উদাহরণস্বরূপ)

তারপরে সার্চভিউ (উইজেটটি আপনি মেনু.এক্সএমএল এ রাখতে পারেন) থেকে:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String text) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String text) {
        yourAdapter.getFilter().filter(text);
        return true;
    }
});

আমি এই জাতীয় কিছু ব্যবহার! সূক্ষ্ম এবং জেনেরিক নমুনা কাজ করে!
ম্যাটিউস

: হ্যালো কে আমাকে এই এক সঙ্গে ধাপে Y-পদক্ষেপ সাহায্য করতে পারেন stackoverflow.com/questions/40754174/...
Thorvald Olavsen

সবচেয়ে পরিষ্কার উত্তর!
আদালপরি

4
এটি আপ ভোট দেওয়া উত্তরের চেয়ে অনেক ভাল কারণ কার্য সম্পাদন ফিল্টার পদ্ধতিতে কর্মী থ্রেডে অপারেশন করা হয়।
হুম্ম

1
তবে আপনি একই তালিকাতে বিভিন্ন ভেরিয়েবলের জন্য একটি রেফারেন্স বরাদ্দ করেন। উদাহরণস্বরূপ this.originalList = list; পরিবর্তে আপনার অ্যাডএল ব্যবহার করা উচিত বা অ্যারেলিস্ট কনস্ট্রাক্টরের তালিকাটি পাস করা উচিত
ফ্লোরিয়ান ওয়ালথার

5

কেবল অ্যাডাপ্টারে দুটি অরগেনাল এবং একটি টেম্প তৈরি করে এবং ফিল্টারযোগ্য প্রয়োগ করে

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                final FilterResults oReturn = new FilterResults();
                final ArrayList<T> results = new ArrayList<>();
                if (origList == null)
                    origList = new ArrayList<>(itemList);
                if (constraint != null && constraint.length() > 0) {
                    if (origList != null && origList.size() > 0) {
                        for (final T cd : origList) {
                            if (cd.getAttributeToSearch().toLowerCase()
                                    .contains(constraint.toString().toLowerCase()))
                                results.add(cd);
                        }
                    }
                    oReturn.values = results;
                    oReturn.count = results.size();//newly Aded by ZA
                } else {
                    oReturn.values = origList;
                    oReturn.count = origList.size();//newly added by ZA
                }
                return oReturn;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(final CharSequence constraint,
                                          FilterResults results) {
                itemList = new ArrayList<>((ArrayList<T>) results.values);
                // FIXME: 8/16/2017 implement Comparable with sort below
                ///Collections.sort(itemList);
                notifyDataSetChanged();
            }
        };
    }

কোথায়

public GenericBaseAdapter(Context mContext, List<T> itemList) {
        this.mContext = mContext;
        this.itemList = itemList;
        this.origList = itemList;
    }

সুন্দর সমাধান। আমি দুটি তালিকা তৈরি করেছি এবং একটি সহজ ফিল্টার পদ্ধতি ব্যবহার করেছি। আমি পরবর্তী ক্রিয়াকলাপে কোনও আইটেমের জন্য সঠিক অ্যাডাপ্টারের অবস্থানটি পাস করতে পারি না। আপনি এইগুলির
এজেডাব্লু

4

অ্যাডাপ্টারে:

public void setFilter(List<Channel> newList){
        mChannels = new ArrayList<>();
        mChannels.addAll(newList);
        notifyDataSetChanged();
    }

ক্রিয়াকলাপে:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                newText = newText.toLowerCase();
                ArrayList<Channel> newList = new ArrayList<>();
                for (Channel channel: channels){
                    String channelName = channel.getmChannelName().toLowerCase();
                    if (channelName.contains(newText)){
                        newList.add(channel);
                    }
                }
                mAdapter.setFilter(newList);
                return true;
            }
        });

খুব সহজ, খুব সংক্ষিপ্ত। ধন্যবাদ!! কাজ করে।
অ্যালন শ্লাইডার

3

সঙ্গে অ্যান্ড্রয়েড আর্কিটেকচার উপাদান ব্যবহারের মাধ্যমে LiveData এই সহজে কোন প্রকার সঙ্গে বাস্তবায়ন করা যায় অ্যাডাপ্টার । আপনাকে কেবল নিম্নলিখিত পদক্ষেপগুলি করতে হবে:

1. নীচের উদাহরণের মতো লাইভ ডেটা হিসাবে রুম ডেটাবেস থেকে ফিরে আসতে আপনার ডেটা সেটআপ করুন :

@Dao
public interface CustomDAO{

@Query("SELECT * FROM words_table WHERE column LIKE :searchquery")
    public LiveData<List<Word>> searchFor(String searchquery);
}

2. একটি তৈরি করুন ViewModel আপনার সংযুক্ত করবে আপডেট করার জন্য বস্তু আপনার ডেটা একটি পদ্ধতি মাধ্যমে বাস দাও এবং আপনার ইউআই

public class CustomViewModel extends AndroidViewModel {

    private final AppDatabase mAppDatabase;

    public WordListViewModel(@NonNull Application application) {
        super(application);
        this.mAppDatabase = AppDatabase.getInstance(application.getApplicationContext());
    }

    public LiveData<List<Word>> searchQuery(String query) {
        return mAppDatabase.mWordDAO().searchFor(query);
    }

}

3. থেকে আপনার ডেটা কল ViewModel নীচের হিসাবে onQueryTextListener মাধ্যমে ক্যোয়ারীতে ক্ষণস্থায়ী দ্বারা মাছি করুন:

নীচে onCreateOptionsMenuআপনার শ্রোতাদের ভিতরে সেট করুন

searchView.setOnQueryTextListener(onQueryTextListener);

নীচে আপনার অনুসন্ধানের শ্রেণীর কোথাও আপনার ক্যোয়ার শ্রোতাদের সেটআপ করুন

private android.support.v7.widget.SearchView.OnQueryTextListener onQueryTextListener =
            new android.support.v7.widget.SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    getResults(query);
                    return true;
                }

                @Override
                public boolean onQueryTextChange(String newText) {
                    getResults(newText);
                    return true;
                }

                private void getResults(String newText) {
                    String queryText = "%" + newText + "%";
                    mCustomViewModel.searchQuery(queryText).observe(
                            SearchResultsActivity.this, new Observer<List<Word>>() {
                                @Override
                                public void onChanged(@Nullable List<Word> words) {
                                    if (words == null) return;
                                    searchAdapter.submitList(words);
                                }
                            });
                }
            };

দ্রষ্টব্য : পদক্ষেপ (১.) এবং (২) স্ট্যান্ডার্ড এএসি ভিউমোডেল এবং ডিএও বাস্তবায়ন, এখানে কেবলমাত্র আসল "যাদু" চলছে অনক্যুরি টেক্সটলিস্টারে যা ক্যোরির পাঠ্য পরিবর্তনের সাথে সাথে আপনার তালিকার ফলাফলগুলিকে পরিবর্তনশীল আপডেট করবে।

বিষয়টি সম্পর্কে আপনার আরও স্পষ্টতা প্রয়োজন হলে জিজ্ঞাসা করতে দ্বিধা করবেন না। আমি আশা করি এটি সাহায্য করেছে :)।


1

ফিল্টারিং অ্যানিমেশনটি হারাতে না পেরে @ ক্লিমেট উত্তরটি প্রসারণ করার ক্ষেত্রে এটি আমার গ্রহণ।

public void filter(String query){
    int completeListIndex = 0;
    int filteredListIndex = 0;
    while (completeListIndex < completeList.size()){
        Movie item = completeList.get(completeListIndex);
        if(item.getName().toLowerCase().contains(query)){
            if(filteredListIndex < filteredList.size()) {
                Movie filter = filteredList.get(filteredListIndex);
                if (!item.getName().equals(filter.getName())) {
                    filteredList.add(filteredListIndex, item);
                    notifyItemInserted(filteredListIndex);
                }
            }else{
                filteredList.add(filteredListIndex, item);
                notifyItemInserted(filteredListIndex);
            }
            filteredListIndex++;
        }
        else if(filteredListIndex < filteredList.size()){
            Movie filter = filteredList.get(filteredListIndex);
            if (item.getName().equals(filter.getName())) {
                filteredList.remove(filteredListIndex);
                notifyItemRemoved(filteredListIndex);
            }
        }
        completeListIndex++;
    }
}

মূলত এটি যা করে তা হ'ল সম্পূর্ণ তালিকাটি অনুসন্ধান করে এবং একে একে ফিল্টার তালিকায় আইটেমগুলি যুক্ত / সরানো।


0

অ্যাডাপ্টারের পিছনের তালিকাটি ফিল্টার তালিকার চেয়ে ছোট আকারের এবং ইনডেক্সআউটঅফবাউন্ডসেক্সপশন ঘটেছে বলে অনুসন্ধানের পাঠ্য (ফিল্টারটি আর কাজ করে না) সরিয়ে দেওয়ার পরে কোনও সমস্যা এড়াতে নীচে নীচে দুটি জিনিস দিয়ে @ জাভার কাপেলারের সমাধান পরিবর্তন করার পরামর্শ দিচ্ছি। সুতরাং নীচের মত কোডটি পরিবর্তন করতে হবে

public void addItem(int position, ExampleModel model) {
    if(position >= mModel.size()) {
        mModel.add(model);
        notifyItemInserted(mModel.size()-1);
    } else {
        mModels.add(position, model);
        notifyItemInserted(position);
    }
}

এবং মুভ আইটেম কার্যকারিতাতেও পরিবর্তন করুন

public void moveItem(int fromPosition, int toPosition) {
    final ExampleModel model = mModels.remove(fromPosition);
    if(toPosition >= mModels.size()) {
        mModels.add(model);
        notifyItemMoved(fromPosition, mModels.size()-1);
    } else {
        mModels.add(toPosition, model);
        notifyItemMoved(fromPosition, toPosition); 
    }
}

আশা করি এটি আপনাকে সহায়তা করতে পারে!


এটি মোটেই প্রয়োজন হয় না।
জাভার কাপেলার

আসল উত্তরের জন্য যদি আপনি এটি না করেন যে সূচকগুলি ছাড়িয়ে গেছে, তবে কেন প্রয়োজন হবে না ???? আপনি কি লগ চান? @ জাভারকাপেলার
টয়ডভি

আপনি যদি Adapterভুল উপায়ে বাস্তবায়ন করেন তবেই ব্যতিক্রম ঘটবে না। আপনার কোডটি না দেখে আমি অনুমান করি সবচেয়ে সম্ভবত সমস্যাটি হ'ল আপনি সমস্ত আইটেমের সাথে তালিকার একটি অনুলিপিটি পাস করছেন না Adapter
জাভের ক্যাপেলার

ত্রুটি লগ: W / System.err: java.lang.IndexOutOfBoundsException: অবৈধ সূচী 36, আকার 35 ডাব্লু / সিস্টেম.অর: জাভা.ইটি.এল.আরলিলিস্ট.থ্রোআইন্ডেক্সআউটঅফবাউন্ডসএক্সসেপশন (অ্যারেলিস্ট.জভা বর্ধিত 55) ডাব্লু / সিস্টেম.আরআর: java.util.ArrayList.add এ (অ্যারেলিস্ট.জভা ১৪7)) ডাব্লু / সিস্টেম.আরআর: com.quomodo.inploi.ui.adapter.M MultipleSelectFilterAdapter.addItem (মাল্টিপলসিলিটফিল্টারএডাপ্টার.জভা অনুচ্ছেদ 25) ডাব্লু / সিস্টেম.আরআর: এ .quomodo.inploi.ui.adapter.Mલ્ટplepleSelectFilterAdapter.applyAndAninateAdditions (একাধিকসিলিটফিল্টারআডাপ্টার.জভা:78)
টয়ডেভি

দয়া করে নীচের সোর্স কোডটি পরীক্ষা করতে সহায়তা করুন @ জাভার
টয়িডভি

0

অনুসন্ধানদর্শন এবং ক্লিকলিস্টারের সাথে পুনর্ব্যবহারযোগ্য

আপনার অ্যাডাপ্টারে একটি ইন্টারফেস যুক্ত করুন।

public interface SelectedUser{

    void selectedUser(UserModel userModel);

}

আপনার মূল কার্যক্ষমতায় ইন্টারফেসটি প্রয়োগ করুন এবং পদ্ধতিটিকে ওভাররাইড করুন। @ ওভাররাইড পাবলিক অকার্যকর নির্বাচিত ব্যবহারকারী (ইউজারমোডেল ব্যবহারকারীমোডেল) {

    startActivity(new Intent(MainActivity.this, SelectedUserActivity.class).putExtra("data",userModel));



}

সম্পূর্ণ টিউটোরিয়াল এবং উত্স কোড: অনুসন্ধানদর্শন এবং অনক্লিক্লিসটেনারের সাথে পুনর্ব্যবহারযোগ্য


-1

লিঙ্কটি এতে কিছু পরিবর্তন করে ব্যবহার করে একই সমস্যাটি সমাধান করেছি। কার্ডগুলির সাথে রিসাইক্লারভিউতে ফিল্টার অনুসন্ধান করুন। এটা কি সম্ভব?(আশাকরি এটা সাহায্য করবে).

এখানে আমার অ্যাডাপ্টার ক্লাস

public class ContactListRecyclerAdapter extends RecyclerView.Adapter<ContactListRecyclerAdapter.ContactViewHolder> implements Filterable {

Context mContext;
ArrayList<Contact> customerList;
ArrayList<Contact> parentCustomerList;


public ContactListRecyclerAdapter(Context context,ArrayList<Contact> customerList)
{
    this.mContext=context;
    this.customerList=customerList;
    if(customerList!=null)
    parentCustomerList=new ArrayList<>(customerList);
}

   // other overrided methods

@Override
public Filter getFilter() {
    return new FilterCustomerSearch(this,parentCustomerList);
}
}

// ফিল্টার ক্লাস

import android.widget.Filter;
import java.util.ArrayList;


public class FilterCustomerSearch extends Filter
{
private final ContactListRecyclerAdapter mAdapter;
ArrayList<Contact> contactList;
ArrayList<Contact> filteredList;

public FilterCustomerSearch(ContactListRecyclerAdapter mAdapter,ArrayList<Contact> contactList) {
    this.mAdapter = mAdapter;
    this.contactList=contactList;
    filteredList=new ArrayList<>();
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
    filteredList.clear();
    final FilterResults results = new FilterResults();

    if (constraint.length() == 0) {
        filteredList.addAll(contactList);
    } else {
        final String filterPattern = constraint.toString().toLowerCase().trim();

        for (final Contact contact : contactList) {
            if (contact.customerName.contains(constraint)) {
                filteredList.add(contact);
            }
            else if (contact.emailId.contains(constraint))
            {
                filteredList.add(contact);

            }
            else if(contact.phoneNumber.contains(constraint))
                filteredList.add(contact);
        }
    }
    results.values = filteredList;
    results.count = filteredList.size();
    return results;
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
    mAdapter.customerList.clear();
    mAdapter.customerList.addAll((ArrayList<Contact>) results.values);
    mAdapter.notifyDataSetChanged();
}

}

// কার্যকলাপের ক্লাস class

public class HomeCrossFadeActivity extends AppCompatActivity implements View.OnClickListener,OnFragmentInteractionListener,OnTaskCompletedListner
{
Fragment fragment;
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_homecrossfadeslidingpane2);CardView mCard;
   setContentView(R.layout.your_main_xml);}
   //other overrided methods
  @Override
   public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.

    MenuInflater inflater = getMenuInflater();
    // Inflate menu to add items to action bar if it is present.
    inflater.inflate(R.menu.menu_customer_view_and_search, menu);
    // Associate searchable configuration with the SearchView
    SearchManager searchManager =
            (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView =
            (SearchView) menu.findItem(R.id.menu_search).getActionView();
    searchView.setQueryHint("Search Customer");
    searchView.setSearchableInfo(
            searchManager.getSearchableInfo(getComponentName()));

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            if(fragment instanceof CustomerDetailsViewWithModifyAndSearch)
                ((CustomerDetailsViewWithModifyAndSearch)fragment).adapter.getFilter().filter(newText);
            return false;
        }
    });



    return true;
}
}

অনকুইয়ারকিস্টেক্সট চেঞ্জলিস্টনার () পদ্ধতিতে আপনার অ্যাডাপ্টার ব্যবহার করুন। আমার অ্যাডপ্টারটি খণ্ডে থাকায় আমি এটিকে টুকরো টুকরো টুকরো করে ফেলেছি। আপনার অ্যাডাপ্টারটি যদি আপনার ক্রিয়াকলাপ শ্রেণিতে থাকে তবে আপনি সরাসরি এটি ব্যবহার করতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.