Когда я делаю недействительными () мои данные, onChanged submitList запускается с 0 элементами, прежде чем loadInitial получает данные из firebase - PullRequest
0 голосов
/ 21 февраля 2019

Я использую библиотеку подкачки с Firebase и устанавливаю ValueEventListener в хранилище, чтобы сделать данные недействительными при каждом изменении.Проблема в том, что как только я запускаю invalidate(), триггер наблюдателя onChanged и Adapter.submitList(items) получает элементы с размером 0, прежде чем новая дата загружается из Firebase с помощью метода loadInitial в ItemKeyedDataSource.

В результате DIFF_CALLBACK никогда не вызывается на PagedListAdapter, потому что нет сравнения между старым списком и списком новых элементов (размер 0), и когда полученные данные обновляют список, как будтоЯ использовал notifyDataSetChanged().

Пока единственное решение - задержать Adapter.submitList(items) на 5 секунд, пока все данные не будут получены из Firebase, но это не практичное решение.

public class UsersRepository {

    private final static String TAG = UsersRepository.class.getSimpleName();

    // [START declare_database_ref]
    private DatabaseReference mDatabaseRef;
    private DatabaseReference mUsersRef;
    private Boolean isFirstLoaded = true;
    public ValueEventListener usersChangesListener;

    public UsersRepository() {
        mDatabaseRef = FirebaseDatabase.getInstance().getReference();
        mUsersRef = mDatabaseRef.child("users");
        isFirstLoaded = true;
        Log.d(TAG, "UsersRepository init. isFirstLoaded= " + isFirstLoaded);

    }

    public void getUsers(Long initialKey, final int size, @NonNull final ItemKeyedDataSource.LoadInitialCallback < User > callback) {
        if (initialKey == null) {
            Log.d(TAG, "getUsers initialKey= " + initialKey);
            mUsersRef.orderByChild("created").limitToFirst(size).addListenerForSingleValueEvent(new ValueEventListener() {@Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    // [START_EXCLUDE]
                    if (dataSnapshot.exists()) {
                        // loop throw users value
                        List < User > usersList = new ArrayList < >();
                        for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
                            usersList.add(userSnapshot.getValue(User.class));
                            Log.d(TAG, "getUsers dataSnapshot. getSnapshotKey= " + userSnapshot.getKey());
                        }

                        if (usersList.size() == 0) {
                            return;
                        }

                        Log.d(TAG, "getUsers usersList.size= " + usersList.size() + " lastkey= " + usersList.get(usersList.size() - 1).getCreatedLong());

                        if (callback instanceof ItemKeyedDataSource.LoadInitialCallback) {

                            //initial load
                            /*((ItemKeyedDataSource.LoadInitialCallback)callback)
                                .onResult(usersList, 0, 14);*/
                            callback.onResult(usersList);
                        }

                    } else {
                        Log.w(TAG, "getUsers no users exist");
                    }

                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    // Getting Post failed, log a message
                    Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
                }
            });
        } else {
            Log.d(TAG, "getUsers initialKey= " + initialKey);
            mUsersRef.orderByChild("created").startAt(initialKey).limitToFirst(size).addListenerForSingleValueEvent(new ValueEventListener() {@Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    // [START_EXCLUDE]
                    if (dataSnapshot.exists()) {
                        // loop throw users value
                        List < User > usersList = new ArrayList < >();
                        for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
                            usersList.add(userSnapshot.getValue(User.class));
                            Log.d(TAG, "getUsers dataSnapshot. getSnapshotKey= " + userSnapshot.getKey());
                        }

                        if (usersList.size() == 0) {
                            return;
                        }

                        Log.d(TAG, "getUsers usersList.size= " + usersList.size() + " lastkey= " + usersList.get(usersList.size() - 1).getCreatedLong());

                        if (callback instanceof ItemKeyedDataSource.LoadInitialCallback) {

                            //initial load
                            /*((ItemKeyedDataSource.LoadInitialCallback)callback)
                                .onResult(usersList, 0, 14);*/
                            callback.onResult(usersList);
                        }

                    } else {
                        Log.w(TAG, "getUsers no users exist");
                    }

                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    // Getting Post failed, log a message
                    Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
                }
            });
        }
    }

    public void getUsersAfter(final Long key, final int size, @NonNull final ItemKeyedDataSource.LoadCallback < User > callback) {
        /*if(key == entireUsersList.get(entireUsersList.size()-1).getCreatedLong()){
            Log.d(TAG, "getUsersAfter init. afterKey= " +  key+ "entireUsersList= "+entireUsersList.get(entireUsersList.size()-1).getCreatedLong());
            return;
        }*/

        Log.d(TAG, "getUsersAfter. AfterKey= " + key);
        mUsersRef.orderByChild("created").startAt(key).limitToFirst(size).addListenerForSingleValueEvent(new ValueEventListener() {@Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                // [START_EXCLUDE]
                if (dataSnapshot.exists()) {
                    // loop throw users value
                    List < User > usersList = new ArrayList < >();
                    for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
                        usersList.add(userSnapshot.getValue(User.class));
                        Log.d(TAG, "getUsersAfter dataSnapshot. getSnapshotKey= " + userSnapshot.getKey());
                    }

                    if (usersList.size() == 0) {
                        return;
                    }

                    Log.d(TAG, "getUsersAfter usersList.size= " + usersList.size() + "lastkey= " + usersList.get(usersList.size() - 1).getCreatedLong());

                    if (callback instanceof ItemKeyedDataSource.LoadCallback) {

                        //initial After
                        callback.onResult(usersList);
                        /*((ItemKeyedDataSource.LoadCallback)callback)
                                .onResult(usersList);*/
                    }

                } else {
                    Log.w(TAG, "getUsersAfter no users exist");
                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                // Getting Post failed, log a message
                Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
            }
        });
        //mUsersRef.addValueEventListener(usersListener);
    }

    public void getUsersBefore(final Long key, final int size, @NonNull final ItemKeyedDataSource.LoadCallback < User > callback) {
        Log.d(TAG, "getUsersBefore. BeforeKey= " + key);

        /*if(key == entireUsersList.get(0).getCreatedLong()){
            return;
        }*/
        mUsersRef.orderByChild("created").endAt(key).limitToLast(size).addListenerForSingleValueEvent(new ValueEventListener() {@Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                // [START_EXCLUDE]
                if (dataSnapshot.exists()) {
                    // loop throw users value
                    List < User > usersList = new ArrayList < >();
                    for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
                        usersList.add(userSnapshot.getValue(User.class));
                        Log.d(TAG, "getUsersBefore dataSnapshot. getSnapshotKeys= " + userSnapshot.getKey());
                    }

                    if (usersList.size() == 0) {
                        return;
                    }

                    Log.d(TAG, "getUsersBefore usersList.size= " + usersList.size() + "lastkey= " + usersList.get(usersList.size() - 1).getCreatedLong());

                    if (callback instanceof ItemKeyedDataSource.LoadCallback) {

                        //initial before
                        callback.onResult(usersList);
                        /*((ItemKeyedDataSource.LoadCallback)callback)
                                .onResult(usersList);*/
                    }
                    //initial load
                    /* ((ItemKeyedDataSource.LoadCallback)callback)
                                .onResult(usersList, 0, usersList.size());*/
                } else {
                    Log.w(TAG, "getUsersBefore no users exist");
                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                // Getting Post failed, log a message
                Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
            }
        });
        //mUsersRef.addValueEventListener(usersListener);
    }

    public void usersChanged(final DataSource.InvalidatedCallback InvalidatedCallback) {

        final Query query = mUsersRef.orderByChild("created");

        usersChangesListener = new ValueEventListener() {

            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (!isFirstLoaded) {
                    isFirstLoaded = true;
                    Log.d(TAG, "entireUsersList Invalidated:");
                    // Remove post value event listener
                    if (usersChangesListener != null) {
                        query.removeEventListener(usersChangesListener);
                        Log.d(TAG, "usersChanged Invalidated removeEventListener");
                    }
                    ((ItemKeyedDataSource.InvalidatedCallback)InvalidatedCallback).onInvalidated();
                }

                isFirstLoaded = false;
                /*if(entireUsersList.size() > 0){
                    entireUsersList.clear();
                    ((ItemKeyedDataSource.InvalidatedCallback)onInvalidatedCallback).onInvalidated();
                    Log.d(TAG, "entireUsersList Invalidated:");
                    return;
                }

                if (dataSnapshot.exists()) {
                    // loop throw users value
                    for (DataSnapshot userSnapshot: dataSnapshot.getChildren()){
                        entireUsersList.add(userSnapshot.getValue(User.class));
                    }

                    Log.d(TAG, "entireUsersList size= "+entireUsersList.size()+"dataSnapshot count= "+dataSnapshot.getChildrenCount());

                } else {
                    Log.w(TAG, "usersChanged no users exist");
                }*/
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                // Getting Post failed, log a message
                Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
                // ...
            }
        };
        query.addValueEventListener(usersChangesListener);
        //mUsersRef.addValueEventListener(eventListener);
    }
}

public class UsersDataSource extends ItemKeyedDataSource < Long,
User >

public class UsersDataSource extends ItemKeyedDataSource < Long,
User > {

    private final static String TAG = UsersDataSource.class.getSimpleName();

    private UsersRepository usersRepository;

    public UsersDataSource() {
        usersRepository = new UsersRepository();
    }

    @Override
    public void addInvalidatedCallback(@NonNull InvalidatedCallback onInvalidatedCallback) {
        //super.addInvalidatedCallback(onInvalidatedCallback);
        Log.d(TAG, "Callback Invalidated ");
        usersRepository.usersChanged(onInvalidatedCallback);
    }

    @Override
    public void loadInitial(@NonNull LoadInitialParams < Long > params, @NonNull LoadInitialCallback < User > callback) {
        /*List<User> items = usersRepository.getUsers(params.requestedInitialKey, params.requestedLoadSize);
        callback.onResult(items);*/
        Log.d(TAG, "loadInitial params key" + params.requestedInitialKey + " " + params.requestedLoadSize);
        usersRepository.getUsers(params.requestedInitialKey, params.requestedLoadSize, callback);
        //usersRepository.getUsers( 0L, params.requestedLoadSize, callback);
    }

    @Override
    public void loadAfter(@NonNull LoadParams < Long > params, @NonNull LoadCallback < User > callback) {
        /*List<User> items = usersRepository.getUsers(params.key, params.requestedLoadSize);
        callback.onResult(items);*/
        Log.d(TAG, "loadAfter params key " + (params.key + 1));
        usersRepository.getUsersAfter(params.key + 1, params.requestedLoadSize, callback);
    }

    @Override
    public void loadBefore(@NonNull LoadParams < Long > params, @NonNull LoadCallback < User > callback) {
        /*List<User> items = fetchItemsBefore(params.key, params.requestedLoadSize);
        callback.onResult(items);*/
        Log.d(TAG, "loadBefore params " + (params.key - 1));
        usersRepository.getUsersBefore(params.key - 1, params.requestedLoadSize, callback);
    }

    @NonNull@Override
    public Long getKey(@NonNull User user) {
        return user.getCreatedLong();
    }
}

public MainFragment()

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

/**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     */
public static MainFragment newInstance(String param1, String param2) {
    MainFragment fragment = new MainFragment();
    Bundle args = new Bundle();
    //fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    /*if(activity != null){
            activity.setTitle(R.string.main_frag_title);
        }*/
    View fragView = inflater.inflate(R.layout.fragment_main, container, false);

    // prepare the Adapter
    mUserArrayList = new ArrayList < >();
    mProfileAdapter = new UsersAdapter();

    // Initiate the viewModel
    viewModel = ViewModelProviders.of(this).get(UsersViewModel.class);

    // Initiate the RecyclerView
    mProfileRecycler = (RecyclerView) fragView.findViewById(R.id.users_recycler);
    mProfileRecycler.setHasFixedSize(true);
    mProfileRecycler.setLayoutManager(new LinearLayoutManager(mActivityContext));

    //viewModel.usersList.observe(this, mProfileAdapter::submitList);
    //viewModel.getPagedListObservable().observe(this, new Observer<PagedList<User>>() {
    viewModel.usersList.observe(this, new Observer < PagedList < User >> () {@Override
        public void onChanged(@Nullable PagedList < User > items) {
            System.out.println("onChanged");

            if (items != null) {
                new java.util.Timer().schedule(
                new java.util.TimerTask() {@Override
                    public void run() {
                        // your code here
                        Log.d(TAG, "submitList size" + items.size());
                        mProfileAdapter.submitList(items);

                    }
                },
                5000);
            }
        }
    });


    mProfileRecycler.setAdapter(mProfileAdapter);

    return fragView;
}

Обновление:

Что ж, я нашел лучшее решение, чем задержка submitList на 5 секунд.Я решил использовать цикл while до тех пор, пока данные не будут получены из базы данных firebase, когда items.size () больше 0, я прекращаю цикл и отправляю список адаптеру.

public class MainFragment extends Fragment {

private final static String TAG = MainFragment.class.getSimpleName();


private RecyclerView mUsersRecycler;
private ArrayList<User> mUserArrayList;
private UsersAdapter mUsersAdapter;

private Context mActivityContext;
private Activity activity;

private UsersViewModel viewModel;
public MainFragment() {
    // Required empty public constructor
}

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 */
public static MainFragment newInstance(String param1, String param2) {
    MainFragment fragment = new MainFragment();
    Bundle args = new Bundle();
    //fragment.setArguments(args);
    return fragment;
}


@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // Initiate viewModel for this fragment instance
    viewModel = ViewModelProviders.of(this).get(UsersViewModel.class);
    //viewModel.getPagedListObservable().observe(this, new Observer<PagedList<User>>() {
    viewModel.usersList.observe(this, new Observer<PagedList<User>>() {
        @Override
        public void onChanged(@Nullable final PagedList<User> items) {
            System.out.println("mama onChanged");
            if (items != null ){

                // Create new Thread to loop until items.size() is greater than 0
                new Thread(new Runnable() {
                    int sleepCounter = 0;
                    @Override
                    public void run() {
                        try {
                            while(items.size()==0) {
                                //Keep looping as long as items size is 0
                                Thread.sleep(20);
                                Log.d(TAG, "sleep 1000. size= "+items.size()+" sleepCounter="+sleepCounter++);
                                if(sleepCounter == 1000){
                                    break;
                                }
                                //handler.post(this);
                            }
                            //Now items size is greater than 0, let's submit the List
                            Log.d(TAG, "after  sleep finished. size= "+items.size());
                            if(items.size() == 0 && sleepCounter == 1000){
                                // If we submit List after loop is finish with 0 results
                                // we may erase another results submitted via newer thread
                                Log.d(TAG, "Loop finished with 0 items. Don't submitList");
                            }else{
                                Log.d(TAG, "submitList");
                                mUsersAdapter.submitList(items);
                            }

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }
                }).start();
            }
        }
    });

}

}

...