【问题标题】:Android firebase getting null [duplicate]Android firebase 为空 [重复]
【发布时间】:2018-05-23 14:53:09
【问题描述】:

我正在使用 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。

【问题讨论】:

    标签: android firebase firebase-realtime-database


    【解决方案1】:

    这是异步 Web API 的一个经典问题:您无法返回尚未加载的内容现在

    Firebase 数据库(以及大多数现代网络 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");
    }
    

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

    附加监听器之前

    附加监听器后

    得到数据

    这可能不是你所期望的,但准确地解释了为什么当你返回它时数组是空的。

    大多数开发人员的最初反应是尝试“修复”这种异步行为。我不建议这样做:网络是异步的,您越早接受这一点,您就能越早学习如何使用现代网络 API 提高工作效率。

    我发现为这种异步范式重构问题最容易。我没有说“首先获取所有视频,然后记录它们”,而是将问题描述为“开始获取所有视频。加载视频后,记录它们”。

    这意味着任何需要视频的代码都必须在 onDataChange() 内(或从那里调用)。例如:

    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 的开发人员来说,这是一个常见的问题。因此,关于这个话题已经有很多问题了,我建议你也去看看:

    【讨论】:

    • 感谢您的回答和您的时间。我会检查这些链接!
    【解决方案2】:

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

    一种解决方案是使用接口回调,这将根据需要将视频列表返回到您的片段:

    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());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-14
      • 2020-02-18
      • 2017-01-20
      • 2016-12-21
      • 1970-01-01
      相关资源
      最近更新 更多