无法在内部类/循环中将元素添加到列表

时间:2019-05-05 12:33:06

标签: java android

我要保存在“名称”列表中找到的所有文档ID。该列表被创建为全局类变量。该代码正在运行,并且documentIds已全部添加到“名称”列表中,但是一旦代码离开内部类(OnComplete),它就会再次被删除。

我知道Java将内部类视为常规类。但是由于它是Override类,因此我无法将任何内容从该类传递回来。我如何仍然可以访问列表的更改?

public class HomeFragment extends Fragment {

    List<String> names = new ArrayList<String>();  

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        return inflater.inflate(R.layout.fragment_home, null);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        addElements();
    }

    public void addElements(){
        db.collection("Recipes").get()
                .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                    @Override
                    public void onComplete(@NonNull Task<QuerySnapshot> task) {
                        if (task.isSuccessful()){
                            for (QueryDocumentSnapshot document : task.getResult()){
                                names.add(document.getId());
                            }
                        }else
                        {
                            //Log
                        }

                    }
                });
    }
}

1 个答案:

答案 0 :(得分:1)

Firebase数据库调用是异步的。从OnCompleteListener(匿名内部类)内部编辑类变量很好,但是您必须了解onComplete中的代码不会立即执行。

db.collection(...).get().addOnCompleteListener(...);的调用采用了您的匿名侦听器类,并启动了一个后台进程来获取数据(在另一个线程上)。该函数立即返回。后台进程完成数据提取后,便会在您提供给它的侦听器上调用onComplete方法(数百到数千毫秒之后)。

例如,如果您按如下所述添加检查,它将首先从名称为size = 0的addElements中打印问候语,然后从名称为> 0的onComplete中打印问候语(假设查询返回了数据)。在发生这种情况之后,您可以在需要的地方使用names(只要Fragment不被破坏,这些值将保留在该位置),但是必须将代码设置为能够等待它发生。

public void addElements(){
    // This runs 1st
    System.out.println("Starting addElements");

    db.collection("Recipes").get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {
                    if (task.isSuccessful()){
                        for (QueryDocumentSnapshot document : task.getResult()){
                            names.add(document.getId());
                        }
                    }else
                    {
                        //Log
                    }

                    // This runs 3rd! in the future when the database call is complete
                    System.out.println("HELLO FROM ONCOMPLETE");
                    printNamesSize();

                    // If you are showing "names" in a UI element, you would
                    // most likely need to call a method to update the 
                    // UI element here, once it's gotten the names
                }
            });

    // This runs 2nd, but names will be empty here (hasn't run onComplete yet)
    System.out.println("HELLO FROM ADDELEMENTS");
    printNamesSize();

    // If your code immediately tries to use names after calling addElements
    // it will still be empty, it hasn't finished the database call yet
}

void printNamesSize() {
    System.out.println("  names size = " + names.size());
}