Пользовательский TiledDataSource с библиотекой подкачки

Я попытался реализовать пользовательский TiledDataSource для использования с библиотекой подкачки. Когда я использовал LivePagedListProvider like return type для моего метода Dao, он работал нормально (после обновления элементов таблицы - ui обновлялся автоматически).

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

Но когда я пытаюсь реализовать пользовательский TiledDataSource для LivePagerListProvider обновлений таблиц, мои наблюдатели не срабатывают.

Абстрактный универсальный класс:

    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());
    }
}

Мой метод дао для этого случая:

@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 (не очень хорошее решение, но это простой способ представить состояние элементов пользовательского интерфейса). После PlayerStateEntity обновлений таблицы Room должен уведомлять об изменении данных, но не делает этого.

Я понимаю, что Room не знает о запросе, который я использовал, и не может обновлять свой RecyclerView, предоставляемый библиотекой подкачки. Но, может быть, кто-то знает, как уведомить Room о таблицах, которые я использовал в моем DataSource для запуска обновлений пользовательского интерфейса в будущем?


person Alex    schedule 02.11.2017    source источник
comment
как "table updates" выглядит?   -  person pskink    schedule 02.11.2017
comment
@pskink Я обновил свой вопрос. Спасибо.   -  person Alex    schedule 02.11.2017
comment
я все еще не могу увидеть loadFromDb реализацию, но взгляните на RoomDatabase#getInvalidationTracker() и DataSource#invalidate()   -  person pskink    schedule 02.11.2017
comment
@pskink Я добавил реализацию своего репозитория. Спасибо за совет, попробую.   -  person Alex    schedule 02.11.2017


Ответы (1)


Проблема была связана с кастомной реализацией DataSource. Когда данные изменились, LivePagedListProvider должен создать новый экземпляр DataSource для обновления правого пользовательского интерфейса. Я использовал тот же экземпляр, поэтому мое предыдущее решение неверно.

person Alex    schedule 02.11.2017