- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
通过用更新的查询替换适配器来实时过滤从 Firestore 填充的 RecyclingView 显示出非常差的性能。
要在我的应用程序中实时过滤 RecyclerView
(onQueryTextChange
),我正在使用扩展 FirestoreRecyclerAdapter
的自定义适配器,每次我需要过滤数据 我创建一个新的 Query
对象,创建新的 FirestoreRecyclerOptions
对象,然后创建我的自定义适配器对象,我将 FirestoreRecyclerOptions
对象传递给 FirestoreRecyclerAdapter
构造函数,最后我在我的 RecyclerView
上调用了 swapAdapter
。这种方法的问题在于它会导致性能不佳。每次更新查询时,我都可以看到 View 在闪烁。
DocumentSearchActivity.java
package com.example.testapp;
import android.app.Activity;
import android.app.SearchManager;
import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.view.inputmethod.InputMethodManager;
import android.widget.SearchView;
import android.widget.TextView;
import com.example.testapp.adapter.ItemAdapter;
import com.example.testapp.model.Item;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
public class DocumentSearchActivity extends AppCompatActivity {
private static final String TAG = DocumentSearchActivity.class.getSimpleName();
private RecyclerView mRecyclerView;
private ItemAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private TextView mNoResultsTextView;
private SearchView mSearchView;
private FirestoreQuery mQuery;
private Toolbar mToolbar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_document_search);
mToolbar = findViewById(R.id.app_bar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
mRecyclerView = findViewById(R.id.recycler_view);
mSearchView = findViewById(R.id.search_bar);
mNoResultsTextView = findViewById(R.id.result);
mNoResultsTextView.setVisibility(View.GONE);
if(getIntent().hasExtra(MainActivity.QUERY_EXTRA)){
mSearchView.setQuery(getIntent().getStringExtra(MainActivity.QUERY_EXTRA), true);
mSearchView.requestFocus();
}
mQuery = new FirestoreQuery(this, "");
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
Intent intent = getIntent();
if(Intent.ACTION_SEARCH.equals(intent.getAction())) {
mQuery.setQueryString(intent.getStringExtra(SearchManager.QUERY));
}
mAdapter = new ItemAdapter(mQuery.getOptions());
mRecyclerView.setAdapter(mAdapter);
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
mAdapter = new ItemAdapter(mQuery.setQueryString(newText).getOptions());
mRecyclerView.swapAdapter(mAdapter, true);
mAdapter.notifyDataSetChanged();
mAdapter.startListening();
return true;
}
});
}
private void runLayoutAnimation(final RecyclerView recyclerView) {
final Context context = recyclerView.getContext();
final LayoutAnimationController controller =
AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_fall_down);
recyclerView.setLayoutAnimation(controller);
recyclerView.getAdapter().notifyDataSetChanged();
recyclerView.scheduleLayoutAnimation();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.actions_document_search_activity, menu);
return super.onCreateOptionsMenu(menu);
}
private class FirestoreQuery {
private LifecycleOwner mLifecycleOwner;
private String mQueryString;
private Query mQuery;
private FirestoreRecyclerOptions<Item> mOptions;
public FirestoreQuery(LifecycleOwner lifecycleOwner, String query) {
mLifecycleOwner = lifecycleOwner;
setQueryString(query);
}
public FirestoreQuery setQueryString(String queryString) {
if(queryString.length() != 0)
this.mQueryString = queryString.substring(0,1).toUpperCase() + queryString.substring(1).toLowerCase();
else
this.mQueryString = queryString;
updateQuery();
updateOptions();
return this;
}
private void updateOptions() {
mOptions = new FirestoreRecyclerOptions.Builder<Item>()
.setQuery(mQuery, Item.class)
.setLifecycleOwner(mLifecycleOwner)
.build();
}
private void updateQuery() {
if(mQueryString.isEmpty()){
this.mQuery = FirebaseFirestore.getInstance()
.collection("tubes_test")
.orderBy("number");
} else {
StringBuilder query_lower = new StringBuilder(mQueryString.length());
query_lower.append(mQueryString);
query_lower.setCharAt(mQueryString.length() - 1, (char) (query_lower.charAt(mQueryString.length() - 1) + 1));
if (mQueryString.matches("^[0-9]{1,3}[A-Z]*$")) {
this.mQuery = FirebaseFirestore.getInstance()
.collection("tubes_test")
.whereGreaterThanOrEqualTo("number", mQueryString)
.whereLessThan("number", query_lower.toString());
} else {
this.mQuery = FirebaseFirestore.getInstance()
.collection("tubes_test")
.whereGreaterThanOrEqualTo("name", mQueryString)
.whereLessThan("name", query_lower.toString());
}
}
}
public FirestoreRecyclerOptions<Item> getOptions() {
return mOptions;
}
}
}
ItemAdapter.java
package com.example.testapp.adapter;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.example.testapp.DocumentViewerActivity;
import com.example.testapp.R;
import com.example.testapp.model.Item;
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
public class ItemAdapter extends FirestoreRecyclerAdapter<Item, ItemAdapter.ItemHolder> {
public ItemAdapter(@NonNull FirestoreRecyclerOptions<Item> options) {
super(options);
}
@Override
protected void onBindViewHolder(@NonNull ItemHolder holder, int position, @NonNull Item item) {
final String tubeNumber = item.getNumber();
holder.mNumberTextView.setText(item.getNumber());
holder.mNameTextView.setText(item.getName());
holder.mFormulaTextView.setText(item.getFormula());
holder.mRangeTextView.setText(item.getRange());
holder.mInfoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), DocumentViewerActivity.class);
intent.putExtra("number", tubeNumber);
intent.putExtra("doctype", "info");
v.getContext().startActivity(intent);
}
});
holder.mManualButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), DocumentViewerActivity.class);
intent.putExtra("number", tubeNumber);
intent.putExtra("doctype", "manual");
v.getContext().startActivity(intent);
}
});
}
@NonNull
@Override
public ItemHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View tubeView = inflater.inflate(R.layout.item_tube, viewGroup, false);
return new ItemHolder(tubeView);
}
public static class ItemHolder extends RecyclerView.ViewHolder {
public TextView mNumberTextView;
public TextView mNameTextView;
public TextView mFormulaTextView;
public TextView mRangeTextView;
public Button mInfoButton;
public Button mManualButton;
public ItemHolder(View itemView){
super(itemView);
mNumberTextView = itemView.findViewById(R.id.number);
mNameTextView = itemView.findViewById(R.id.name);
mFormulaTextView = itemView.findViewById(R.id.formula);
mRangeTextView = itemView.findViewById(R.id.range);
mInfoButton = itemView.findViewById(R.id.info_btn);
mManualButton = itemView.findViewById(R.id.manual_btn);
}
}
}
不知道有没有更好的办法解决这个问题。此外,我不想失去 Firestore 的功能,例如实时数据更新和离线访问数据库。我正在考虑在我的适配器中使用可过滤列表,问题是我如何使它与 Firestore 保持同步。请分享您的见解和指南。
最佳答案
这是对我有用的解决方案。基本上,我创建了一个自定义可过滤适配器,我只用来自 Firestore 的数据填充一次。
CustomItemAdapter.java
package com.example.testapp.adapter;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import com.example.testapp.DocumentViewerActivity;
import com.example.testapp.R;
import com.example.testapp.model.Item;
import java.util.ArrayList;
import java.util.List;
public class CustomItemAdapter extends RecyclerView.Adapter<CustomItemAdapter.ItemHolder> implements Filterable {
private List<Item> mTubeList;
private List<Item> mTubeListFiltered;
public CustomItemAdapter(List<Item> tubeList){
mTubeList = tubeList;
mTubeListFiltered = tubeList;
}
@NonNull
@Override
public ItemHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View tubeView = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_tube, viewGroup, false);
return new ItemHolder(tubeView);
}
@Override
public void onBindViewHolder(@NonNull ItemHolder holder, int i) {
final Item item = mTubeListFiltered.get(i);
//Setting up view
}
@Override
public int getItemCount() {
return mTubeListFiltered.size();
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String pattern = constraint.toString().toLowerCase();
if(pattern.isEmpty()){
mTubeListFiltered = mTubeList;
} else {
List<Item> filteredList = new ArrayList<>();
for(Item tube: mTubeList){
if(tube.getNumber().toLowerCase().contains(pattern) || tube.getName().toLowerCase().contains(pattern)) {
filteredList.add(tube);
}
}
mTubeListFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = mTubeListFiltered;
return filterResults;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mTubeListFiltered = (ArrayList<Item>) results.values;
notifyDataSetChanged();
}
};
}
public static class ItemHolder extends RecyclerView.ViewHolder {
//ViewHolder's code
}
}
Activity fragment :
Query query = FirebaseFirestore.getInstance()
.collection("test")
.orderBy("number");
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
mAdapter = new CustomItemAdapter(task.getResult().toObjects(Item.class));
mRecyclerView.setAdapter(mAdapter);
}
});
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
mAdapter.getFilter().filter(newText);
return true;
}
});
关于android - 如何为从 Firestore 填充的 RecyclerView 实现过滤器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54369948/
我是一名优秀的程序员,十分优秀!