带有分页库的自定义 TiledDataSource

Custom TiledDataSource with paging library

我尝试实现自定义 TiledDataSource 以与分页库一起使用。当我为我的 Dao 方法使用 LivePagedListProvider 之类的 returns 类型时,它工作正常(在 table 项目更新后 - ui 自动更新)。

@Query("SELECT * FROM " + Table.States.PLAY_STATE + ", "+Table.Chart.ARTIST+ " ORDER BY position ASC")
LivePagedListProvider<Artist> loadArtists();

但是当我尝试为 LivePagerListProvider table 实施自定义 TiledDataSource 时,更新没有触发我的观察者。

抽象泛型 class:

    public abstract class PagedNetworkBoundResource<ResultType, RequestType> extends TiledDataSource<ResultType> {

    @Override
    public int countItems() {
        return DataSource.COUNT_UNDEFINED;
    }

    @Override
    public List<ResultType> loadRange(int startPosition, int count) {
        fetchFromNetwork(startPosition, count);
        return loadFromDb(startPosition, count);
    }

    @WorkerThread
    private void fetchFromNetwork(int startPosition, int count) {
        if (createCall(startPosition, count) != null)
            try {
                Response<RequestType> response = createCall(startPosition, count).execute();
                if (response.isSuccessful() && response.code() == 200) {
                    saveCallResult(response.body());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    }

    @WorkerThread
    protected abstract void saveCallResult(@NonNull RequestType item);


    @WorkerThread
    protected abstract List<ResultType> loadFromDb(int startPosition, int count);

    @WorkerThread
    protected abstract Call<RequestType> createCall(int startPosition, int count);

    public LiveData<PagedList<ResultType>> getAsLiveData() {
        return new LivePagedListProvider<Integer, ResultType>() {
            @Override
            protected DataSource<Integer, ResultType> createDataSource() {
                return PagedNetworkBoundResource.this;
            }

        }.create(0, new PagedList.Config.Builder()
                .setEnablePlaceholders(false)
                .setPageSize(20)
                .setInitialLoadSizeHint(20)
                .build());
    }
}

本例我的dao方法:

@Query("SELECT * FROM " + Table.States.PLAY_STATE + ", "+Table.Chart.ARTIST+ " ORDER BY position ASC LIMIT (:limit) OFFSET (:offset)")
List<Artist> loadArtists(int offset, int limit);

我更新Table.States.PLAY_STATE.

 public void updatePlayerState(PlayerStateEntity state){
        new Thread(() -> {
            dao.deleteState();
            dao.insertState(state);
        }).run();
    }


 @Dao
public interface PlayStateDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertState(PlayerStateEntity playEntity);

    @Query("DELETE FROM " + Table.States.PLAY_STATE)
    void deleteState();

    @Query("SELECT * FROM "+Table.States.PLAY_STATE)
    PlayerStateEntity getPlayerState();
}

@Entity(tableName = Table.States.PLAY_STATE)
public class PlayerStateEntity extends IdEntity {

    @ColumnInfo(name = "album_played_id")
    private Long albumPlayedId = -1L;

    @ColumnInfo(name = "track_played_id")
    private Long trackPlayedId = -1L;

    @ColumnInfo(name = "artist_played_id")
    private Long artistPlayedId = -1L;


    @ColumnInfo(name = "state")
    private PlayingState state;

    @ColumnInfo(name = "playing_type")
    private PlayingType playingType;

    public Long getAlbumPlayedId() {
        return albumPlayedId;
    }

    public void setAlbumPlayedId(Long albumPlayedId) {
        this.albumPlayedId = albumPlayedId;
    }

    public Long getTrackPlayedId() {
        return trackPlayedId;
    }

    public void setTrackPlayedId(Long trackPlayedId) {
        this.trackPlayedId = trackPlayedId;
    }

    public Long getArtistPlayedId() {
        return artistPlayedId;
    }

    public void setArtistPlayedId(Long artistPlayedId) {
        this.artistPlayedId = artistPlayedId;
    }

    public PlayingState getState() {
        return state;
    }

    public void setState(PlayingState state) {
        this.state = state;
    }

    public PlayingType getPlayingType() {
        return playingType;
    }

    public void setPlayingType(PlayingType playingType) {
        this.playingType = playingType;
    }
}

 class Artist extends PlayEntity{
    private String name;
    private String link;
    private String picture;
    @ColumnInfo(name = "picture_small")
    private String pictureSmall;
    @ColumnInfo(name = "picture_medium")
    private String pictureMedium;
    @ColumnInfo(name = "picture_big")
    private String pictureBig;
    @ColumnInfo(name = "picture_xl")
    private String pictureXl;
    private Boolean radio;
    private String tracklist;
    private Integer position;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLink() {
        return link;
    }

    public void setLink(String link) {
        this.link = link;
    }

    public String getPicture() {
        return picture;
    }

    public void setPicture(String picture) {
        this.picture = picture;
    }

    public String getPictureSmall() {
        return pictureSmall;
    }

    public void setPictureSmall(String pictureSmall) {
        this.pictureSmall = pictureSmall;
    }

    public String getPictureMedium() {
        return pictureMedium;
    }

    public void setPictureMedium(String pictureMedium) {
        this.pictureMedium = pictureMedium;
    }

    public String getPictureBig() {
        return pictureBig;
    }

    public void setPictureBig(String pictureBig) {
        this.pictureBig = pictureBig;
    }

    public String getPictureXl() {
        return pictureXl;
    }

    public void setPictureXl(String pictureXl) {
        this.pictureXl = pictureXl;
    }

    public Boolean getRadio() {
        return radio;
    }

    public void setRadio(Boolean radio) {
        this.radio = radio;
    }

    public String getTracklist() {
        return tracklist;
    }

    public void setTracklist(String tracklist) {
        this.tracklist = tracklist;
    }

    public Integer getPosition() {
        return position;
    }

    public void setPosition(Integer position) {
        this.position = position;
    }

    @Override
    public boolean isItemPlaying() {
        return getId() == getArtistPlayedId().longValue() && getPlayingType() == PlayingType.Artist && getState() == PlayingState.Playing;
    }
}

public abstract class PlayEntity extends PlayerStateEntity {

  public abstract boolean isItemPlaying();
}

public class ArtistsRepository {
    private final ChartArtistDao chartArtistDao;
    private final DeezerService deezerService;


    @Inject
    public ArtistsRepository(ChartArtistDao chartArtistDao, DeezerService deezerService) {
        this.chartArtistDao = chartArtistDao;
        this.deezerService = deezerService;
    }


    public LiveData<PagedList<ChartArtistDao.Artist>> getArtist() {



        return new PagedNetworkBoundResource<ChartArtistDao.Artist, ModelList<ChartArtistEntity>>() {

            @Override
            protected void saveCallResult(@NonNull ModelList<ChartArtistEntity> item) {
                if (item != null) {
                    chartArtistDao.saveArtists(item.getItems());
                }
            }

            @Override
            protected List<ChartArtistDao.Artist> loadFromDb(int startPosition, int count) {
                return chartArtistDao.loadArtists(startPosition, count);
            }

            @Override
            protected Call<ModelList<ChartArtistEntity>> createCall(int startPosition, int count) {
                return deezerService.getChartArtist(startPosition, count);
            }

        }.getAsLiveData();
    }
}

对于每个 Artist 项目,我添加来自 PlayerStateEntity 的字段(不是好的解决方案,但这是表示 ui 项目状态的简单方法)。 PlayerStateEntity table 更新后 Room 应该通知数据更改,但没有这样做。

我知道 Room 不知道查询我使用了什么,也无法更新我的分页库提供的 RecyclerView。但也许有人知道如何通知 Room 我在我的数据源中使用的 tables 用于将来触发 ui 更新?

问题与自定义 DataSource 实现有关。当数据发生变化时,LivePagedListProvider 应该创建一个新的 DataSource 实例以进行正确的 ui 更新。我用的是同一个实例,所以我之前的方案不对。