带有分页库的自定义 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 更新。我用的是同一个实例,所以我之前的方案不对。
我尝试实现自定义 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 更新。我用的是同一个实例,所以我之前的方案不对。