Android firebase 为空 [重复]

Posted

技术标签:

【中文标题】Android firebase 为空 [重复]【英文标题】:Android firebase getting null [duplicate] 【发布时间】: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。

【问题讨论】:

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

Setting Singleton property value in Firebase Listener Handle data returned by an Async task (Firebase)(展示如何定义和传入你自己的回调) Firebase - android - fetchProvidersForEmail - Why are all the calls asynchronous?(还有很多其他类似问题的链接)

【讨论】:

感谢您的回答和您的时间。我会检查这些链接!【参考方案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());

【讨论】:

以上是关于Android firebase 为空 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 动态链接始终为空

Android Firebase 奇怪的数据映射

Firebase Android - 如何随机获取一些项目[重复]

Android Studio中的Firebase android jars文档/javadoc [重复]

Android Studio和Firebase中的权限被拒绝错误[重复]

无法从 Android 中的 Firebase 存储获取下载网址 [重复]