当前位置: 首页 > 知识库问答 >
问题:

Android firebase获取空值[重复]

冉丰茂
2023-03-14

我在用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个答案

全丰
2023-03-14

它返回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());
芮建茗
2023-03-14

这是异步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");
}

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

在附加侦听器之前

附加侦听器后

有数据吗

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

大多数开发人员最初的反应是尝试“修复”这种异步行为。我建议不要这样做:网络是异步的,你越早接受这一点,你就能越早学会如何使用现代网络应用编程接口变得高效。

我发现为这个异步范例重新定义问题是最容易的。我没有说“先获取所有视频,然后记录它们”,而是将问题定义为“开始获取所有视频。加载视频后,记录它们”。

这意味着任何需要视频的代码都必须在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的开发人员来说,这是一个常见的问题。因此,关于这个话题已经有很多问题了,我建议你也去看看:

  • 在Firebase侦听器中设置单例属性值
  • 处理异步任务(Firebase)返回的数据(显示如何html" target="_blank">定义和传递自己的回调)
  • Firebase-Android-fetchProvidersForEmail-为什么所有调用都是异步的?(还有更多类似问题的链接)
 类似资料:
  • 问题内容: 我正在编写一个非常简单的查询,但是由于某种原因,我得到了重复的值。 在返回重复值。即: 但是,直接在mysql中运行此查询 不返回重复值。 谁能发现哪里出了问题? 问题答案: 快速的解决方法是使用“不同的根实体结果转换器”。 但这只是一个工作环境。 我怀疑问题属于您的映射。如果从ProcessInstance到其他对象之间急切地加载了1:n关系(称为X),并且一个ProcessInst

  • 我创建了一个简单的REST服务(POST)。但是当我从postman@RequestBody调用这个服务时,它没有收到任何值。 我的java Bean对象如下: System.out.println将null打印为PolcyNumber的值。 请帮我解决这个问题。 我在请求体中传递的JSON是 我甚至在postman中设置了到

  • 我想让对话框片段(DialogFragment)向我返回一个值,该值是在退出时在编辑数量(editQuantity)中输入的。 但我没有办法让它发挥作用。我可以通过将值传递给intent来实现这一点,但这会破坏当前活动的进度。 除了传递意图之外,还有什么方法可以返回我的值吗?

  • 我已经使用API从API中提取了JSON响应,请放心,它看起来像这样: 现在,我实际的JSON响应在JSON数组中有数千个JSON对象,一些键有空值,例如“secondKey”在一些JSON对象中有空值。我需要获取JSON响应中所有空值的键。对我该如何做有什么想法吗? 我解决这个问题的想法是使用Jackson库反序列化JSON并获取所有空值。然而,考虑到性能,是否有任何有效的解决方案?

  • 我到处寻找,并尽一切努力从SQLQueriesRadion按钮获取选定的mySQL值。 这是我的密码 谢啦

  • 问题内容: 我有以下数组: 结果: 现在如何显示具有重复值的键?在此函数不应返回([0],[9]),因为没有重复的值。 如何找到相同值的键,例如 对于“ 2011-06-25”,应返回[7],[8] 问题答案: 函数名称显然很长;) 现在$ dups将包含一个由重复值键控的多维数组,其中包含每个重复项的键,如果您将“ true”作为第二个参数发送,它将返回没有重复值的原始数组。 或者,您可以将原始