Intereting Posts
Как программно удалить журналы вызовов из android? Можно ли использовать VectorDrawable в кнопках и TextViews с помощью Android: DrawableRight? Изменение размера растрового изображения в Android Учебное пособие для камеры для Android (с использованием поверхностного обзора) Может ли Android renderscript работать на GPU? Добавить фиксированную кнопку внутри scrollview, которая видна даже при прокрутке Как создать диалог оповещений с многострочным заголовком? Как я могу получить доступ к моему локальному хосту с моего устройства Android? Как записывать журнал модема в Android Как сделать звуковой сигнал в андроиде? Управление соединениями SQLite на Android Принесите маркеры карт Google на передний план, изменив Z-Index на Android Невозможно получить PDF-файл в виде двоичных данных Для отладки Android JNI / NDK в Eclipse, почему мои точки останова игнорируются? Будет ли обработчик PostDelayed не запускаться, когда процессор спит?

Использование GeoFire для заполнения Firebase Recycler View в android

Я хочу заполнить вид моего ресайклера, чтобы я мог видеть, кем являются люди / места поблизости. Я использую GeoFire для запроса моей базы данных, которая выглядит примерно так.

GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(latLngCenter.latitude, latLngCenter.longitude), 0.1); geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() { @Override public void onKeyEntered(String key, GeoLocation location) { System.out.println(String.format("Key %s entered the search area at [%f,%f]", key, location.latitude, location.longitude)); Log.e("TAG", key + location.latitude + location.longitude); } @Override public void onKeyExited(String key) { System.out.println(String.format("Key %s is no longer in the search area", key)); } @Override public void onKeyMoved(String key, GeoLocation location) { System.out.println(String.format("Key %s moved within the search area to [%f,%f]", key, location.latitude, location.longitude)); Log.e("TAG", key + location.latitude + location.longitude); } @Override public void onGeoQueryReady() { System.out.println("All initial data has been loaded and events have been fired!"); } @Override public void onGeoQueryError(DatabaseError error) { System.err.println("There was an error with this query: " + error); } }); 

И я использую этот Firebase RecyclerView

  RecyclerView recycler = (RecyclerView) findViewById(R.id.RecyclerView); recycler.setHasFixedSize(true); recycler.setLayoutManager(new LinearLayoutManager(this)); FirebaseRecyclerAdapter<Chat, ChatHolder> mAdapter = new FirebaseRecyclerAdapter<Chat, ChatHolder>(Chat.class, R.layout.recyclerview, ChatHolder.class, mUsers) { @Override public void populateViewHolder(final ChatHolder chatMessageViewHolder, final Chat chatMessage, int position) { chatMessageViewHolder.setName(chatMessage.getName()); chatMessageViewHolder.setText(chatMessage.getText()); chatMessageViewHolder.setTimestamp(chatMessage.getTimestamp()); } }; recycler.setAdapter(mAdapter); 

С этим классом класса чата и классом объектов чата

 public static class ChatHolder extends RecyclerView.ViewHolder { View mView; public ChatHolder(View itemView) { super(itemView); mView = itemView; } public void setName(String name) { TextView field = (TextView) mView.findViewById(R.id.textViewName); field.setText(name); } public void setText(String text) { TextView field = (TextView) mView.findViewById(R.id.textViewMessage); field.setText(text); } public void setTimestamp(String text) { TextView field = (TextView) mView.findViewById(R.id.textViewTime); field.setText(text); } } public static class Chat { String name; String text; String uid; String timestamp; public Chat() { } public Chat(String name, String uid, String message, String timestamp) { this.name = name; this.text = message; this.uid = uid; this.timestamp = timestamp; } public String getName() { return name; } public String getUid() { return uid; } public String getText() { return text; } public String getTimestamp() { return timestamp; } } 

В настоящее время этот адаптер, который предоставляется в библиотеке FirebaseUI, заполняет recyclerview, так что используется только одна ссылка, и все дочерние события отображаются в представлении. Теперь я хочу заполнить свой recyclerView, чтобы когда когда-либо входит ключ, он заполняет мой recyclerview Основанный на моем ключе = к моей ссылке, это как моя база данных firebase смотрит мою базу данных firebase

Solutions Collecting From Web of "Использование GeoFire для заполнения Firebase Recycler View в android"

Это пользовательский FirebaseListAdapter от Emanuelet, из которого я создал FirebaseRecyclerAdapter.

  public abstract class FirebaseRecyclerAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH > implements Filterable { private static final String LOG_TAG = "FirebaseListAdapter"; private Query mRef; private Class<T> mModelClass; private int mLayout; private LayoutInflater mInflater; protected Class<VH> mViewHolderClass; private List<T> mModels; private List<T> mFilteredModels; private List<String> mKeys = new ArrayList<>(); private Map<String, T> mModelKeys; private Map<String, T> mFilteredKeys; private ChildEventListener mListener; private FirebaseRecyclerAdapter.ValueFilter valueFilter; /** * @param mRef The Firebase location to watch for data changes. Can also be a slice of a location, using some * combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>, * @param mModelClass Firebase will marshall the data at a location into an instance of a class that you provide * @param mLayout This is the mLayout used to represent a single list item. You will be responsible for populating an * instance of the corresponding view with the data from an instance of mModelClass. * @param activity The activity containing the ListView */ public FirebaseRecyclerAdapter(Query mRef, Class<T> mModelClass, int mLayout, Activity activity, Class<VH> viewHolderClass) { this.mRef = mRef; this.mModelClass = mModelClass; this.mLayout = mLayout; this.mViewHolderClass = viewHolderClass; mInflater = activity.getLayoutInflater(); mModels = new ArrayList<>(); mModelKeys = new HashMap<>(); // Look for all child events. We will then map them to our own internal ArrayList, which backs ListView mListener = this.mRef.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { T model = dataSnapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass); mModelKeys.put(dataSnapshot.getKey(), model); // Insert into the correct location, based on previousChildName if (previousChildName == null) { mModels.add(0, model); } else { T previousModel = mModelKeys.get(previousChildName); int previousIndex = mModels.indexOf(previousModel); int nextIndex = previousIndex + 1; if (nextIndex == mModels.size()) { mModels.add(model); mKeys.add(dataSnapshot.getKey()); } else { mModels.add(nextIndex, model); mKeys.add(dataSnapshot.getKey()); } } notifyDataSetChanged(); } @Override public void onChildChanged(DataSnapshot dataSnapshot, String s) { Log.d(LOG_TAG, "onChildChanged"); // One of the mModels changed. Replace it in our list and name mapping String modelName = dataSnapshot.getKey(); T oldModel = mModelKeys.get(modelName); T newModel = dataSnapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass); int index = mModels.indexOf(oldModel); mModels.set(index, newModel); mModelKeys.put(modelName, newModel); notifyDataSetChanged(); } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { Log.d(LOG_TAG, "onChildRemoved"); // A model was removed from the list. Remove it from our list and the name mapping String modelName = dataSnapshot.getKey(); T oldModel = mModelKeys.get(modelName); mModels.remove(oldModel); mKeys.remove(dataSnapshot.getKey()); mModelKeys.remove(modelName); notifyDataSetChanged(); } @Override public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) { Log.d(LOG_TAG, "onChildMoved"); // A model changed position in the list. Update our list accordingly String modelName = dataSnapshot.getKey(); T oldModel = mModelKeys.get(modelName); T newModel = dataSnapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass); int index = mModels.indexOf(oldModel); mModels.remove(index); if (previousChildName == null) { mModels.add(0, newModel); mKeys.add(dataSnapshot.getKey()); } else { T previousModel = mModelKeys.get(previousChildName); int previousIndex = mModels.indexOf(previousModel); int nextIndex = previousIndex + 1; if (nextIndex == mModels.size()) { mModels.add(newModel); mKeys.add(dataSnapshot.getKey()); } else { mModels.add(nextIndex, newModel); mKeys.add(dataSnapshot.getKey()); } } notifyDataSetChanged(); } @Override public void onCancelled(DatabaseError error) { Log.e("FirebaseListAdapter", "Listen was cancelled, no more updates will occur"); } }); } public void cleanup() { // We're being destroyed, let go of our mListener and forget about all of the mModels mRef.removeEventListener(mListener); mModels.clear(); mModelKeys.clear(); mKeys.clear(); } @Override public int getItemCount() { return mModels.size(); } public T getItem(int position) { return mModels.get(position); } @Override public void onBindViewHolder(VH holder, int position) { T model = getItem(position); populateViewHolder(holder, model, position, mKeys); } @Override public long getItemId(int i) { return i; } @Override public int getItemViewType(int position) { return mLayout; } public void remove(String key) { T oldModel = mModelKeys.get(key); mModels.remove(oldModel); mKeys.remove(key); mModelKeys.remove(key); notifyDataSetChanged(); } @Override public VH onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false); try { Constructor<VH> constructor = mViewHolderClass.getConstructor(View.class); return constructor.newInstance(view); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Each time the data at the given Firebase location changes, this method will be called for each item that needs * to be displayed. The arguments correspond to the mLayout and mModelClass given to the constructor of this class. * <p/> * Your implementation should populate the view using the data contained in the model. * * @param viewHolder The view to populate * @param model The object containing the data used to populate the view */ protected abstract void populateViewHolder(VH viewHolder, T model, int position, List<String> mKeys); public void addSingle(DataSnapshot snapshot) { T model = snapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass); mModelKeys.put(snapshot.getKey(), model); mModels.add(model); mKeys.add(snapshot.getKey()); notifyDataSetChanged(); } public void update(DataSnapshot snapshot, String key) { T oldModel = mModelKeys.get(key); T newModel = snapshot.getValue(FirebaseRecyclerAdapter.this.mModelClass); int index = mModels.indexOf(oldModel); if (index >= 0) { mModels.set(index, newModel); mModelKeys.put(key, newModel); notifyDataSetChanged(); } } public boolean exists(String key) { return mModelKeys.containsKey(key); } @Override public Filter getFilter() { if (valueFilter == null) { valueFilter = new FirebaseRecyclerAdapter.ValueFilter(); } return valueFilter; } protected abstract List<T> filters(List<T> models, CharSequence constraint); private class ValueFilter extends Filter { //Invoked in a worker thread to filter the data according to the constraint. @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new Filter.FilterResults(); if (mFilteredModels == null) { mFilteredModels = new ArrayList<>(mModels); // saves the original data in mOriginalValues mFilteredKeys = new HashMap<>(mModelKeys); // saves the original data in mOriginalValues } if (constraint != null && constraint.length() > 0) { List<T> filtered = filters(mFilteredModels, constraint); results.count = filtered.size(); results.values = filtered; mModelKeys = filterKeys(mModels); } else { results.count = mFilteredModels.size(); results.values = mFilteredModels; mModelKeys = mFilteredKeys; } return results; } //Invoked in the UI thread to publish the filtering results in the user interface. @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { Log.d(LOG_TAG, "filter for " + constraint + ", results nr: " + results.count); mModels = (List<T>) results.values; notifyDataSetChanged(); } } protected abstract Map<String, T> filterKeys(List<T> mModels); } 

Расширьте приложение PostsQueryAdapter с помощью FirebaseRecyclerAdapter

 public class FirebasePostsQueryAdapter extends FirebaseRecyclerAdapter<Feeds, PostViewHolder> { Activity mActivity; /** * @param mRef The Firebase location to watch for data changes. Can also be a slice of a location, using some * combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>, * @param mLayout This is the mLayout used to represent a single list item. You will be responsible for populating an * instance of the corresponding view with the data from an instance of mModelClass. * @param activity The activity containing the ListView * @param viewHolderClass This is the PostsViewHolder Class which will be used to populate data. */ Query query; public FirebasePostsQueryAdapter(Query mRef, int mLayout, Activity activity, Class<PostViewHolder> viewHolderClass) { super(mRef, Feeds.class, mLayout, activity, viewHolderClass); this.query = mRef; this.mActivity = activity; } @Override protected void populateViewHolder(final PostViewHolder viewHolder, final Feeds model, final int position, final List<String> mKeys) { viewHolder.setPhoto(model.getThumb_url()); viewHolder.setTimestamp(DateUtils.getRelativeTimeSpanString( (long) model.getTimestamp()).toString()); viewHolder.setAuthor(model.getUser().getFull_name(), model.getUser().getUid()); viewHolder.setIcon(model.getUser().getProfile_picture(), model.getUser().getUid()); viewHolder.setText(model.getText()); viewHolder.mPhotoView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(mActivity, SingleVideoView.class); intent.putExtra(Constants.INTENT_VIDEO,model.getVideo_url()); intent.putExtra(Constants.KEY, mKeys.get(position)); mActivity.startActivity(intent); } }); ValueEventListener likeListener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { viewHolder.setNumLikes(dataSnapshot.getChildrenCount()); if (dataSnapshot.hasChild(FirebaseUtil.getCurrentUserId())) { viewHolder.setLikeStatus(PostViewHolder.LikeStatus.LIKED, mActivity); } else { viewHolder.setLikeStatus(PostViewHolder.LikeStatus.NOT_LIKED, mActivity); } } @Override public void onCancelled(DatabaseError databaseError) { } }; FirebaseUtil.getLikesRef().child(mKeys.get(position)).addValueEventListener(likeListener); viewHolder.mLikeListener = likeListener; } @Override protected List<Feeds> filters(List<Feeds> models, CharSequence constraint) { return null; } @Override protected Map<String, Feeds> filterKeys(List<Feeds> mModels) { return null; } } 

Где вы заполняете данные в FirebasePostsQueryAdapter

  @Override public void onCreate() { super.onCreate(); mFirebaseRef = FirebaseDatabase.getInstance().getReference(POSTS_STRING); mFirebaseRef.keepSynced(true); this.geoFire = new GeoFire(FirebaseDatabase.getInstance().getReference(GEO_POINTS)); mItemListAdapter = new FirebasePostQueryAdapter(mFirebaseRef.equalTo(GEOFIRE_CHILD), getActivity(), R.layout.list_item_items); } @Override public void onConnected(Bundle bundle) { startLocationUpdates(); center = new GeoLocation(MainActivity.mLastLocation.getLatitude(), MainActivity.mLastLocation.getLongitude()); if (!mActiveGeoQuery) { center = new GeoLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude()); startGeoQuery(); mAdapter.notifyDataSetChanged(); } center = new GeoLocation(MainActivity.mLastLocation.getLatitude(), MainActivity.mLastLocation.getLongitude()); if (center.latitude != 0 && center.longitude != 0 && !mActiveGeoQuery) { startGeoQuery(); } else if (mActiveGeoQuery) { Log.d(TAG, "geoquery already active"); } else { Log.d(TAG, "center not setted"); //I first try to set the center at the Last Known Location if retrieved if (Double.isNaN(mCurrentLocation.getLatitude()) && mCurrentLocation.getLatitude() != 0) { center = new GeoLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude()); startGeoQuery(); } } fragment.checkForItems(); } private void startGeoQuery() { query = geoFire.queryAtLocation(center, 2); Log.d(TAG, "center: " + center.toString() + ", radius: " + 2); query.addGeoQueryEventListener(new GeoQueryEventListener() { @Override public void onKeyEntered(String key, GeoLocation location) { Log.d(TAG, "Key " + key + " entered the search area at [" + location.latitude + "," + location.longitude + "]"); DatabaseReference tempRef = mFirebaseRef.child(key); tempRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // I add the deal only if it doesn't exist already in the adapter String key = snapshot.getKey(); if (!mAdapter.exists(key)) { Log.d(TAG, "item added " + key); mAdapter.addSingle(snapshot); mAdapter.notifyDataSetChanged(); } else { //...otherwise I will update the record Log.d(TAG, "item updated: " + key); mAdapter.update(snapshot, key); mAdapter.notifyDataSetChanged(); } } @Override public void onCancelled(DatabaseError databaseError) { } }); } @Override public void onKeyExited(String key) { Log.d(TAG, "deal " + key + " is no longer in the search area"); mAdapter.remove(key); fragment.isListEmpty(); } @Override public void onKeyMoved(String key, GeoLocation location) { Log.d(TAG, String.format("Key " + key + " moved within the search area to [%f,%f]", location.latitude, location.longitude)); DatabaseReference tempRef = mFirebaseRef.child(key); tempRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // I add the deal only if it doesn't exist already in the adapter String key = snapshot.getKey(); if (!mAdapter.exists(key)) { Log.d(TAG, "item added " + key); mAdapter.addSingle(snapshot); mAdapter.notifyDataSetChanged(); } else { //...otherwise I will update the record Log.d(TAG, "item updated: " + key); mAdapter.update(snapshot, key); mAdapter.notifyDataSetChanged(); } } @Override public void onCancelled(DatabaseError databaseError) { } }); } @Override public void onGeoQueryReady() { Log.d(TAG, "All initial data has been loaded and events have been fired!"); fragment.isListEmpty(); mActiveGeoQuery = true; } @Override public void onGeoQueryError(DatabaseError error) { Log.e(TAG, "There was an error with this query: " + error); mActiveGeoQuery = false; } }); fragment.bindRecyclerView(); } 

Будет проще проталкивать все данные (которые также являются uid ), которые вы извлекли из геофила, в новый узел, чтобы хранить результаты геофонии в firebase, что-то вроде

 my-node //your new firebase node to store all uids retrieved from geofire - {chatUid}: true //true is just a dummy data, you can use anything else except null and empty string. - {chatUid}: true - ... 

И установите для FirebaseRecyclerAdapter ref этот узел.

 DatabaseReference ref = FirebaseDatabase.getInstance().getReference("my-node"); FirebaseRecyclerAdapter fra = new FirebaseRecyclerAdapter<Boolean, MyVH>(Boolean.class, R.layout.my_layout, MyVH.class, ref) { ... } 

А затем в методе populateViewHolder() в вашей реализации FirebaseRecyclerAdapter вы можете использовать клавишу String для извлечения данных с основного узла, который содержит данные.

 public void populateViewHolder(MyVH viewHolder, Boolean model, int position){ // Get references of child views final TextView nameTextView = viewHolder.getItemView().findViewById(R.id.my_name_text_view_in_vh_layout); final TextView addressTextView = viewHolder.getItemView().findViewById(R.id.my_address_text_view_in_vh_layout); // Key in this position. String key = getRef(position).key; // Query the full data of the current key located in the `main-data-node` FirebaseDatabase.getInstance().getReference("main-data-node").child(key).addValueEventListener(new ValueEventListener(){ ... //Truncated onCancelled @Override public void onDataChange(snap: DataSnapshot){ MyDataModel model = snap.getValue(MyDataModel.class); nameTextView = model.getName(); addressTextView = model.getAddress(); } } } // The data model class public class MyDataModel { private String name; private String address; ... // Truncated getter, setter, constructor } 

Для любых изменений результата geofire просто нажмите эти результаты на my-node , и он автоматически сообщит ваш FirebaseRecyclerAdapter .

PS Я слишком ленив, чтобы соответствовать моему решению вашей модели данных (извините), поэтому я сделал упрощенный класс образцов, поэтому, если кто-нибудь наткнулся на это, они могут понять это проще.

PSS Прошло некоторое время, так как я код в java, я в основном использую kotlin (и вы скоро должны слишком lol), поэтому, если есть некоторые ошибки синтаксиса, не стесняйтесь редактировать.