FirebaseRecyclerAdapter的populateViewHolder方法中的“addListenerForSingleValueEvent”在Firebase引用下的数据更改时被调用

时间:2017-02-27 01:46:25

标签: android firebase firebase-realtime-database android-location firebaseui

我在我的应用中使用FirebaseRecyclerAdapter并尝试通过在其populateViewHolder()方法中提取一些数据来填充它,然后将值分配给不同的参数。

这是我的代码:

private void attachRecyclerViewAdapter() {
        Query lastFifty = aReference.child(requestID).limitToFirst(50);
        mRecyclerViewAdapter = new FirebaseRecyclerAdapter<AModelClass, AModelClass.ViewHolder>(
                AModelClass.class, R.layout.a_layout, AModelClass.ViewHolder.class, lastFifty) {

            @Override
            protected void populateViewHolder(final AModelClass.ViewHolder viewHolder, AModelClass model, int position) {
                final String key = this.getRef(position).getKey();
                aReference.child(requestID).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        if (dataSnapshot.getValue() != null) {    
                            aReference.child(requestID).child(key).addListenerForSingleValueEvent(new ValueEventListener() {
                                @Override
                                public void onDataChange(DataSnapshot dataSnapshot) {

                                    if (dataSnapshot.getValue() != null) {

                                        if (dataSnapshot.hasChild("pName") && dataSnapshot.hasChild("pUrl") && dataSnapshot.hasChild("currentLat") && dataSnapshot.hasChild("currentLng")) {
                                            final Map<String, String> map = (Map<String, String>) dataSnapshot.getValue();
                                            pA = map.get("pName");
                                            uidP = map.get("pUrl");
                                            nP.add(map.get("pName"));

                                            cLatPlayers.add(map.get("currentLat").trim());
                                            cLngPlayers.add(map.get("currentLng").trim());

                                            viewHolder.setPNameT(pA);
                                            viewHolder.setPicP(uidP);
                                            viewHolder.setCurrentLatAU(String.valueOf(currentLtAU));
                                            viewHolder.setCurrentLngAU(String.valueOf(currentLnAU));

                                            addMarkers();

                                            layout.setVisibility(View.VISIBLE);
                                            progressBar.setVisibility(View.INVISIBLE);
                                        }

                                    } else {
                                    }

                                }

                                @Override
                                public void onCancelled(DatabaseError databaseError) {

                                }
                            });

                        } else {
                            Toast.makeText(getBaseContext(), "no data available yet", Toast.LENGTH_SHORT).show();
                        }

                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });
            }
        };

        mRecyclerViewAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onItemRangeRemoved(int positionStart, int itemCount) {
            }

            @Override
            public void onItemRangeInserted(int positionStart, int itemCount) {
                super.onItemRangeInserted(positionStart, itemCount);
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount) {
                super.onItemRangeChanged(positionStart, itemCount);
            }
        });

        aList.setAdapter(mRecyclerViewAdapter);
    }

attachRecyclerViewAdapter()位于onCreate()

aList中的onCreate()初始化:

aList = (RecyclerView) findViewById(R.id.aList);
aList.setLayoutManager(nLinearLayoutManager);

这是onLocationChanged()方法:

@Override
public void onLocationChanged(Location location) {
        mCurrentLocation = location;
        currentLtAU = mCurrentLocation.getLatitude();
        currentLnAU = mCurrentLocation.getLongitude();

        aReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
        aReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));        
}

,只要在上面检索数据的相同引用下更改位置,就会将更新的lat和lng保存到数据库。

LocationRequest代码:

protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(1000);
        mLocationRequest.setFastestInterval(500);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setSmallestDisplacement(0);
}

这里的一切工作都很顺利,唯一的问题是引用下的代码:aReference.child(requestID).child(key)或(aReference.child(requestID)可能?)被一次又一次地调用(虽然由于addListenerForSingleValueEvent),它应该被调用一次,因此多次填充nPcLatPlayerscLngPlayers,并且addMarkers()方法也被调用多次在Map中引起问题。

为什么会发生这种情况?我怎么能确保不会多次调用它?

2 个答案:

答案 0 :(得分:0)

我怀疑如果您正在获得循环,那么问题就出在您更改值以响应更改的位置。

所以这里:

viewHolder.setPNameT(pA);

尝试做类似的事情:

if (!viewHolder.getPNameT().equals(pA)) {
    viewHolder.setPNameT(pA);
}

因此,只有在值不同的情况下才更新该值,然后它不会注册为更改并触发另一个对侦听器的调用。这样,每次更改只能获得一个循环。

我还没有使用FirebaseRecylcerView(直到现在还不知道它存在),但这是我过去用于TextWatchers的一般方法。这似乎是同样的问题。

答案 1 :(得分:0)

我提出了一个非常简单而有效的解决方案。

我刚刚将更新后的位置保存在数据库中的不同引用中,这样每当它发生更改时,onDataChange()下的aReference.child(requestID)都不会被调用,因此代码不会一次又一次地执行。

我更改了onLocationChanged()下的代码:

@Override
public void onLocationChanged(Location location) {
        mCurrentLocation = location;
        currentLtAU = mCurrentLocation.getLatitude();
        currentLnAU = mCurrentLocation.getLongitude();

        aReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
        aReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));        
} 

到此:

@Override
public void onLocationChanged(Location location) {
        mCurrentLocation = location;
        currentLtAU = mCurrentLocation.getLatitude();
        currentLnAU = mCurrentLocation.getLongitude();

        anotherReference.child(requestID).child(userID).child("currentLatUpdated").setValue(String.valueOf(currentLtAU));
        anotherReference.child(requestID).child(userID).child("currentLngUpdated").setValue(String.valueOf(currentLnAU));        
}

但我仍然无法理解为什么addListenerForSingleValueEvent()每次都会监听数据更改,尽管它应该只监听一次数据更改。