Android firebase获取null

时间:2017-12-09 15:11:21

标签: android firebase firebase-realtime-database

我正在使用Firebase来保存我的数据。我正在尝试将Firebase方法和我的方法分离到活动上。例如,我创建了一个名为“FirebaseMethodsHelper”的类,我想编写所有Firebase方法。 例如,“getAllUsers”方法应该在列表中返回所有用户。 我唯一的问题是它不起作用。

我不知道我做错了什么,所以如果你们请帮助我。

片段

  public class MyPlayListFragment extends Fragment {
    private FirebaseDatabase refToVideos;
    private FirebaseUser currentUser;
    private ArrayList<Video> videosList;
    private VideoViewAdapter adapter;
    private RecyclerView rvVideos;
    private List<Video> checkList;


public MyPlayListFragment() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View v = inflater.inflate(R.layout.fragment_my_play_list, container, false);
    rvVideos = (RecyclerView)v.findViewById(R.id.rvVideos);

    return v;
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    videosList = new ArrayList<>();
    refToVideos = FirebaseDatabase.getInstance();
    currentUser = FirebaseAuth.getInstance().getCurrentUser();

    FirebaseMethodsHelper fmh = new FirebaseMethodsHelper();


    checkList = fmh.getAllVideosFromDB(currentUser);
    if(checkList != null)
    Log.d("checkList",checkList.toString());

FirebaseMethodHelper类

   public class FirebaseMethodsHelper {
private FirebaseDatabase databaseRef;
private ArrayList<User> usersList;
private ArrayList<Video> videosList;



   public List<Video> getAllVideosFromDB(FirebaseUser currentUser){
        databaseRef = FirebaseDatabase.getInstance();
        databaseRef.getReference(Params.VIDEOS).child(currentUser.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                for (DataSnapshot snapshot : dataSnapshot.getChildren()){
                    videosList.add(snapshot.getValue(Video.class));
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });


    return videosList;
  }
 }

我不知道为什么,但它总是返回null。

2 个答案:

答案 0 :(得分:2)

这是异步Web API的典型问题:您无法返回尚未加载的现在

Firebase数据库(和大多数现代Web API)数据是异步加载的,因为它可能需要一些时间。在将数据加载到辅助线程上时,主应用程序代码将继续,而不是等待数据(这将导致用户的应用程序无响应对话框)。然后,当数据可用时,将调用onDataChange()方法并使用该数据。

这会更改您应用的流量。最简单的方法是查看几个日志语句:

public List<Video> getAllVideosFromDB(FirebaseUser currentUser){
    databaseRef = FirebaseDatabase.getInstance();
    System.out.println("Before attaching listener");
    databaseRef.getReference(Params.VIDEOS).child(currentUser.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            System.out.println("Got data");
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            throw databaseError.toException(); // don't ignore errors
        }
    });
    System.out.println("After attaching listener");
}

运行此代码将打印以下序列:

  

在附加监听器之前

     

附加监听器后

     

获得数据

这可能不是您所期望的,但是在您返回数组时,该数组为空的原因正是如此。

大多数开发人员的初步回应是尝试&#34;修复&#34;这种异步行为。我建议不要这样做:网络是异步的,越早接受,就越早了解如何通过现代Web API提高效率。

我发现为这种异步范例重新构建问题最容易。而不是说'#34;首先获取所有视频,然后记录它们&#34;,我将问题定格为&#34;开始获取所有视频。加载视频后,请记录下来&#34;。

这意味着任何需要视频的代码必须位于onDataChange()内(或从内部调用)。 E.g:

public List<Video> getAllVideosFromDB(FirebaseUser currentUser){
    databaseRef = FirebaseDatabase.getInstance();
    databaseRef.getReference(Params.VIDEOS).child(currentUser.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot snapshot : dataSnapshot.getChildren()){
                videosList.add(snapshot.getValue(Video.class));
            }
            if (videosList != null) {
                Log.d("checkList",videosList.toString());
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            throw databaseError.toException(); // don't ignore errors
        }
    });

}

正如我所说,对于以前没有处理异步API的开发人员而言,这是一个常见问题。因此,已经有很多关于这个主题的问题,我建议你也检查一下:

答案 1 :(得分:1)

它返回null,因为列表videosList尚未初始化。此外,您在方法中返回列表的方法是错误的。 firebase调用是异步的,因此您无法控制数据何时可用,因此几乎每次您的方法将返回null(如果列表尚未初始化)或空列表(如果您初始化它)。< / p>

解决方案是使用界面回调,这会根据需要将视频列表返回到您的片段:

public interface FirebaseCallback {
    void listVideos(ArrayList<Video> videos);
}

此方法将从您的FirebaseMethodHelper类调用:

public void getAllVideosFromDB(FirebaseUser currentUser, FirebaseCallback callback){
    databaseRef = FirebaseDatabase.getInstance();
    databaseRef.getReference(Params.VIDEOS).child(currentUser.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            ArrayList<Video> videosList = new ArrayList<>();

            for (DataSnapshot snapshot : dataSnapshot.getChildren()){
                videosList.add(snapshot.getValue(Video.class));
            }

            callback.listVideos(videosList);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });  
}

从您的片段中,您实现了接口并将this传递给方法,如下所示:

public class MyPlayListFragment extends Fragment implements FirebaseCallback  {
    private FirebaseDatabase refToVideos;
    private FirebaseUser currentUser;
    private ArrayList<Video> videosList;
    private VideoViewAdapter adapter;
    private RecyclerView rvVideos;
    private List<Video> checkList;


public MyPlayListFragment() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View v = inflater.inflate(R.layout.fragment_my_play_list, container, false);
    rvVideos = (RecyclerView)v.findViewById(R.id.rvVideos);

    return v;
}
@Override
public void listVideos(ArrayList<Video> videos) {
    //do what you want with the videos
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    videosList = new ArrayList<>();
    refToVideos = FirebaseDatabase.getInstance();
    currentUser = FirebaseAuth.getInstance().getCurrentUser();

    FirebaseMethodsHelper fmh = new FirebaseMethodsHelper();


    checkList = fmh.getAllVideosFromDB(currentUser, this);
    if(checkList != null)
    Log.d("checkList",checkList.toString());