- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试使用 Paging 库 + RxJava 创建应用程序,一切正常,它从后端加载数据并将其插入我的 Recyclerview,当我向下滚动 LoadAfter 正常加载下一页时,我的问题是当我向上滑动时使用 SwipeLayoutRefrech 刷新数据会使数据源无效,它只调用 LoadInitial(仅加载 20 个第一项),而 LoadAfter 根本不调用,我花了很多时间但仍然没有解决方案。
这是我的数据源工厂:
public class GalleryPhotosDataSourceFactory extends DataSource.Factory<Integer, GalleryPhotosItems> {
private CompositeDisposable compositeDisposable;
private MutableLiveData<GalleryPhotosDataSource> DataSourceMutableLiveData = new MutableLiveData<>();
/**
* Create a DataSource.
* <p>
* The DataSource should invalidate itself if the snapshot is no longer valid. If a
* DataSource becomes invalid, the only way to query more data is to create a new DataSource
* from the Factory.
* <p>
* {@link } for example will construct a new PagedList and DataSource
* when the current DataSource is invalidated, and pass the new PagedList through the
* {@code LiveData<PagedList>} to observers.
*
* @return the new DataSource.
*/
public GalleryPhotosDataSourceFactory(CompositeDisposable compositeDisposable) {
this.compositeDisposable = compositeDisposable;
}
@Override
public DataSource<Integer, GalleryPhotosItems> create() {
GalleryPhotosDataSource galleryPhotosDataSource = new GalleryPhotosDataSource(compositeDisposable);
DataSourceMutableLiveData.postValue(galleryPhotosDataSource);
return galleryPhotosDataSource;
}
@NonNull
public MutableLiveData<GalleryPhotosDataSource> getDataSourceLiveData() {
return DataSourceMutableLiveData ;
}
}
我的类数据源用于从我的服务器加载数据:
public class GalleryPhotosDataSource extends ItemKeyedDataSource<Integer, GalleryPhotosItems> {
public static final String TAG = "GalleryPhotosDataSource";
private ApiService apiService;
private CompositeDisposable compositeDisposable;
private MutableLiveData<NetworkState> networkState = new MutableLiveData<>();
private MutableLiveData<NetworkState> initialLoad = new MutableLiveData<>();
/**
* Keep Completable reference for the retry event
*/
private Completable retryCompletable;
GalleryPhotosDataSource(CompositeDisposable compositeDisposable) {
this.apiService = Client.createAppService();
this.compositeDisposable = compositeDisposable;
}
public void retry() {
if (retryCompletable != null) {
compositeDisposable.add(retryCompletable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {
}, throwable -> Timber.e(throwable.getMessage())));
}
}
/**
* Load initial data.
* <p>
* This method is called first to initialize a PagedList with data. If it's possible to count
* the items that can be loaded by the DataSource, it's recommended to pass the loaded data to
* the callback via the three-parameter
* {@link LoadInitialCallback#onResult(List, int, int)}. This enables PagedLists
* presenting data from this source to display placeholders to represent unloaded items.
* <p>
* {@link LoadInitialParams#requestedInitialKey} and {@link LoadInitialParams#requestedLoadSize}
* are hints, not requirements, so they may be altered or ignored. Note that ignoring the
* {@code requestedInitialKey} can prevent subsequent PagedList/DataSource pairs from
* initializing at the same location. If your data source never invalidates (for example,
* loading from the network without the network ever signalling that old data must be reloaded),
* it's fine to ignore the {@code initialLoadKey} and always start from the beginning of the
* data set.
*
* @param params Parameters for initial load, including initial key and requested size.
* @param callback Callback that receives initial load data.
*/
@Override
public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<GalleryPhotosItems> callback) {
// update network states.
// we also provide an initial load state to the listeners so that the UI can know when the
// very first list is loaded.
networkState.postValue(NetworkState.LOADING);
initialLoad.postValue(NetworkState.LOADING);
//get the initial users from the api
compositeDisposable.add(apiService.getPhotosGallery(1, 5, -1, params.requestedLoadSize).subscribe(galleryPhotosItemses -> {
// clear retry since last request succeeded
setRetry(null);
networkState.postValue(NetworkState.LOADED);
initialLoad.postValue(NetworkState.LOADED);
callback.onResult(galleryPhotosItemses);
},
throwable -> {
// keep a Completable for future retry
setRetry(() -> loadInitial(params, callback));
NetworkState error = NetworkState.error(throwable.getMessage());
// publish the error
networkState.postValue(error);
initialLoad.postValue(error);
}));
}
/**
* Load list data after the key specified in {@link LoadParams#key LoadParams.key}.
* <p>
* It's valid to return a different list size than the page size if it's easier, e.g. if your
* backend defines page sizes. It is generally safer to increase the number loaded than reduce.
* <p>
* Data may be passed synchronously during the loadAfter method, or deferred and called at a
* later time. Further loads going down will be blocked until the callback is called.
* <p>
* If data cannot be loaded (for example, if the request is invalid, or the data would be stale
* and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
* and prevent further loading.
*
* @param params Parameters for the load, including the key to load after, and requested size.
* @param callback Callback that receives loaded data.
*/
@Override
public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<GalleryPhotosItems> callback) {
// set network value to loading.
networkState.postValue(NetworkState.LOADING);
//get the users from the api after id
compositeDisposable.add(apiService.getPhotosGallery(1, 5, params.key-1, params.requestedLoadSize).subscribe(galleryPhotosItemses -> {
// clear retry since last request succeeded
setRetry(null);
networkState.postValue(NetworkState.LOADED);
callback.onResult(galleryPhotosItemses);
},
throwable -> {
// keep a Completable for future retry photos_user/5/1534161047_1534160953579.jpg
setRetry(() -> loadAfter(params, callback));
// publish the error
networkState.postValue(NetworkState.error(throwable.getMessage()));
}));
}
/**
* Load list data before the key specified in {@link LoadParams#key LoadParams.key}.
* <p>
* It's valid to return a different list size than the page size if it's easier, e.g. if your
* backend defines page sizes. It is generally safer to increase the number loaded than reduce.
* <p>
* <p class="note"><strong>Note:</strong> Data returned will be prepended just before the key
* passed, so if you vary size, ensure that the last item is adjacent to the passed key.
* <p>
* Data may be passed synchronously during the loadBefore method, or deferred and called at a
* later time. Further loads going up will be blocked until the callback is called.
* <p>
* If data cannot be loaded (for example, if the request is invalid, or the data would be stale
* and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
* and prevent further loading.
*
* @param params Parameters for the load, including the key to load before, and requested size.
* @param callback Callback that receives loaded data.
*/
@Override
public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<GalleryPhotosItems> callback) {
}
/**
* Return a key associated with the given item.
* <p>
* If your ItemKeyedDataSource is loading from a source that is sorted and loaded by a unique
* integer ID, you would return {@code item.getID()} here. This key can then be passed to
* {@link #loadBefore(LoadParams, LoadCallback)} or
* {@link #loadAfter(LoadParams, LoadCallback)} to load additional items adjacent to the item
* passed to this function.
* <p>
* If your key is more complex, such as when you're sorting by name, then resolving collisions
* with integer ID, you'll need to return both. In such a case you would use a wrapper class,
* such as {@code Pair<String, Integer>} or, in Kotlin,
* {@code data class Key(val name: String, val id: Int)}
*
* @param item Item to get the key from.
* @return Key associated with given item.
*/
@NonNull
@Override
public Integer getKey(@NonNull GalleryPhotosItems item) {
return item.getPhoto_id();
}
@NonNull
public MutableLiveData<NetworkState> getNetworkState() {
return networkState;
}
@NonNull
public MutableLiveData<NetworkState> getInitialLoad() {
return initialLoad;
}
private void setRetry(final Action action) {
if (action == null) {
this.retryCompletable = null;
} else {
this.retryCompletable = Completable.fromAction(action);
}
}
}
我的 View 模型:
public class GalleryPhotosViewModel extends ViewModel {
public LiveData<PagedList<GalleryPhotosItems>> photosList;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private static final int pageSize = 10;
private GalleryPhotosDataSourceFactory photosDataSourceFactory;
public GalleryPhotosViewModel() {
photosDataSourceFactory = new GalleryPhotosDataSourceFactory(compositeDisposable);
PagedList.Config config = new PagedList.Config.Builder()
.setPageSize(pageSize)
.setInitialLoadSizeHint(pageSize * 2)
.setEnablePlaceholders(true)
.build();
photosList = new LivePagedListBuilder<>(photosDataSourceFactory, config).build();
}
public void retry() {
photosDataSourceFactory.getDataSourceLiveData().getValue().retry();
}
public void refresh() {
photosDataSourceFactory.getDataSourceLiveData().getValue().invalidate();
}
public LiveData<NetworkState> getNetworkState() {
return Transformations.switchMap(photosDataSourceFactory.getDataSourceLiveData(), GalleryPhotosDataSource::getNetworkState);
}
public LiveData<NetworkState> getRefreshState() {
return Transformations.switchMap(photosDataSourceFactory.getDataSourceLiveData(), GalleryPhotosDataSource::getInitialLoad);
}
@Override
protected void onCleared() {
super.onCleared();
compositeDisposable.dispose();
}
}
最后是我的 initAdapter 和 SwipeRefreshLayout fragment :
public class AbonnesFragment extends Fragment implements RetryCallback{
@BindView(usersSwipeRefreshLayout)
SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.usersRecyclerView)
RecyclerView usersRecyclerView;
@BindView(R.id.errorMessageTextView)
TextView errorMessageTextView;
@BindView(R.id.retryLoadingButton)
Button retryLoadingButton;
@BindView(R.id.loadingProgressBar)
ProgressBar loadingProgressBar;
private GalleryPhotosViewModel viewModel;
private GalleryPhotosAdapter Adapter;
View rootView;
public AbonnesFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_photos, container, false);
ButterKnife.bind(this, rootView);
viewModel = ViewModelProviders.of(this).get(GalleryPhotosViewModel.class);
initAdapter();
initSwipeToRefresh();
return rootView;
}
private void initAdapter() {
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
switch(Adapter.getItemViewType(position)){
case R.layout.gallery_photos_items:
return 1;
case R.layout.item_network_state:
return 3;
default:
return -1;
}
}
});
Adapter = new GalleryPhotosAdapter(this);
usersRecyclerView.setLayoutManager(gridLayoutManager);
usersRecyclerView.setAdapter(Adapter);
viewModel.photosList.observe(this, Adapter::submitList);
viewModel.getNetworkState().observe(this, Adapter::setNetworkState);
}
/**
* Init swipe to refresh and enable pull to refresh only when there are items in the adapter
*/
private void initSwipeToRefresh() {
viewModel.getRefreshState().observe(this, networkState -> {
if (networkState != null) {
if (Adapter.getCurrentList() != null) {
if (Adapter.getCurrentList().size() > 0) {
mSwipeRefreshLayout.setRefreshing(networkState.getStatus() == NetworkState.LOADING.getStatus());
} else {
setInitialLoadingState(networkState);
}
} else {
setInitialLoadingState(networkState);
}
}
});
mSwipeRefreshLayout.setOnRefreshListener(() -> viewModel.refresh());
}
/**
* Show the current network state for the first load when the user list
* in the adapter is empty and disable swipe to scroll at the first loading
*
* @param networkState the new network state
*/
private void setInitialLoadingState(NetworkState networkState) {
//error message
errorMessageTextView.setVisibility(networkState.getMessage() != null ? View.VISIBLE : View.GONE);
if (networkState.getMessage() != null) {
errorMessageTextView.setText(networkState.getMessage());
}
//loading and retry
retryLoadingButton.setVisibility(networkState.getStatus() == Status.FAILED ? View.VISIBLE : View.GONE);
loadingProgressBar.setVisibility(networkState.getStatus() == Status.RUNNING ? View.VISIBLE : View.GONE);
if (networkState.getStatus() == Status.SUCCESS){
mSwipeRefreshLayout.setEnabled(true);
} else {
mSwipeRefreshLayout.setEnabled(false);
}
}
@OnClick(R.id.retryLoadingButton)
void retryInitialLoading() {
viewModel.retry();
}
@Override
public void retry() {
viewModel.retry();
}
}
我希望能找到可以帮助我的人,谢谢
最佳答案
这似乎是一个已报告并已修复的错误 https://issuetracker.google.com/issues/113122599
已在 2.1.0-alpha01 中修复
Fixed a case where an extremely small initial load size together with unchanged data would result in no further loading b/113122599
关于android - Paging库在向上滑动刷新后只调用LoadInitial,不调用LoadAfter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52244969/
Java 库和 android 库有什么区别,各自有什么优点/缺点? 最佳答案 您可以在 Android 应用程序中包含标准 Java .jar 文件库。它们在 .apk 构建时被翻译成 Dalvik
所以,我现在的代码就像从 Java 层加载库(比如 liba.so),并在内部 liba.so 加载 libb.so。因此,如果我必须将所有库打包到 APK 中并将其安装在没有 root 访问权限的设
我想在我的系统中设置 LEDA 库。 我已经从以下链接下载了 LEDA 库 http://www.algorithmic-solutions.info/free/d5.php Instruct
我想用 autoconf 创建一个共享库。但是,我希望共享库具有“.so”扩展名,而不是以“lib”开头。基本上,我想制作一个加载 dlopen 的插件。 .是否有捷径可寻? 当我尝试使用 autoc
我需要在 Apps 脚本应用程序上修改 PDF。为此,我想使用 JS 库:PDF-LIB 我的代码: eval(UrlFetchApp.fetch("https://unpkg.com/pdf-lib
我正在构建一个使用以下 Boost header 的程序(我使用的是 Microsoft Visual C++ 10), #include #include #include #include
当我通过 cygwin 在 hadoop 上运行此命令时: $bin/hadoop jar hadoop-examples-*.jar grep input output 'dfs[a-z.]+' 我
我已经通过 vcpgk 成功安装了一个 C++ 库,名为:lmdb:x64-windows 我还安装了lmdb通过 Cabal 安装的 Haskell 绑定(bind)包 在尝试测试 lmdb 包时:
我该如何解决这个问题? 我刚刚将 javacv jar 文件复制到我的项目 Lib 文件夹下,但出现了这个错误! 我可以找到这个thread来自谷歌,但不幸的是,由于我国的谷歌限制政策,该页面无法打开
我有一个 Android 库项目 FooLib。 FooLib 引用 Android Context 之类的东西,但不需要任何资源文件(res/ 中的东西)所以我目前将其打包为供我的应用使用的 JAR
我正在开发一个 Android 应用程序(使用 Android Studio),它能够通过手势识别算法了解您正在进行的 Activity 。对于我使用 nickgillian ithub 帐户上可用的
关于从 .NET Framework 项目中引用 .NET Standard 类库的问题有很多类似的问题,其中 netstandard 库中的 NuGet 包依赖项不会流向 netframework
我已经从互联网上下载了 jna-4.2.2.jar,现在想将这个 jar 导入到我的项目中。但是当我试图将这个 jar 导入我的项目时,出现以下错误。 [2016-06-20 09:35:01 - F
我正在尝试通过编译在 Mac 上安装 rsync 3.2.3。但是,我想安装所有功能。为此,它需要一些库,此处 ( https://download.samba.org/pub/rsync/INSTA
进入 Web 开发有点困难。过去 5 年我一直致力于 winforms 工作。所以我正在努力从一种切换到另一种。前段时间,我使用过 JavaScript,但现在还没有大量的 JavaScript 库
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我正在寻找一个用Python编写的与logstash(ruby + java)类似的工具/库。 我的目标是: 从 syslog 中解析所有系统日志 解析应用程序特定日志(apache、django、m
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
我花了几天时间试图寻找用于 JavaPOS 实现的 .jar 库,但我找不到任何可以工作的东西。我找到了很多像这样的文档:http://jpos.1045706.n5.nabble.com/file/
这个问题在这里已经有了答案: Merge multiple .so shared libraries (2 个答案) 关闭 9 年前。 我有我在代码中使用的第三方库的源代码和对象。该库附带有关如何使
我是一名优秀的程序员,十分优秀!