Intereting Posts
Хранение идентификаторов R.drawable в массиве XML Необходимо отправить несколько запросов волейбола – в последовательности OnTouchEvent посредством кода с помощью Instrumentation В App Purchase: два устройства с одинаковой учетной записью не получают одинаковые купленные предметы Intent.ACTION_GET_CONTENT с Google Диском AppBarLayout занимает пробел после setVisibility (View.GONE) Android. Получение контекста из широковещательного приемника onReceive () для отправки Время поездки между двумя точками в Google Map Android API V2 «Обнаружение службы не удалось» с Android Bluetooth Insecure Rfcomm Код примера FFmpeg для создания видеофайла из неподвижных изображений JNI Android Динамические ссылки Firebase не имеют глубокой связи с коротким URL-адресом на пользовательских вкладках Экспорт android в csv и отправка в виде вложения электронной почты Как использовать эмулятор Android через VNC Как узнать, какой взгляд сосредоточен? Использование Green DAO с поставщиком контента

Использование 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), поэтому, если есть некоторые ошибки синтаксиса, не стесняйтесь редактировать.