热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从Room观察LiveData会导致PagedListAdapter刷新,ViewModel也会在方向更改时刷新数据

如何解决《从Room观察LiveData会导致PagedListAdapter刷新,ViewModel也会在方向更改时刷新数据》经验,为你挑选了1个好方法。

我正在构建一个使用ArticleBoundaryCallback初始化对API的调用并将响应存储在Room中的应用。我还使用LiveData收听该表,并在PagedListAdapter中显示项目。

问题在于,每次将新数据插入到Room(Article)表中时,整个列表都会刷新。

同样,在配置更改时,似乎再次获取了整个数据(ViewModel不保留它,RecyclerView被重新创建)。

每次插入时,RecyclerView都会跳转(如果插入的是新数据,则跳转几行;如果将新数据替换为旧数据,则跳转到开头)。

整个代码在此GitHub存储库中。

我的课程是:

文章:

@Entity(tableName = "article",
    indices={@Index(value="id")})public class Article {
@PrimaryKey(autoGenerate = false)
@SerializedName("_id")
@Expose
@NonNull
private String id;
@SerializedName("web_url")
@Expose
private String webUrl;
@SerializedName("snippet")
@Expose
private String snippet;
@SerializedName("print_page")
@Expose
private String printPage;
@SerializedName("source")
@Expose
private String source;
@SerializedName("multimedia")
@Expose
@Ignore
private List multimedia = null;

第DAO条:

@Dao
public interface ArticleDao {

@Insert(OnConflict= OnConflictStrategy.REPLACE)
long insert(Article article);

@Insert(OnConflict= OnConflictStrategy.REPLACE)
void update(Article... repos);

@Insert(OnConflict= OnConflictStrategy.REPLACE)
void insertArticles(List
articles); @Delete void delete(Article... articles); @Query("DELETE FROM article") void deleteAll(); @Query("SELECT * FROM article") List
getArticles(); @Query("SELECT * FROM article") DataSource.Factory getAllArticles();}

LocalCache(从会议室存储/检索)

public class LocalCache {
private static final String TAG = LocalCache.class.getSimpleName();
private ArticleDao articleDao;
private Executor ioExecutor;

public LocalCache(AppDatabase appDatabase, Executor ioExecutor) {
    this.articleDao = appDatabase.getArticleDao();
    this.ioExecutor = ioExecutor;
}

public void insertAllArticles(List
articleArrayList){ ioExecutor.execute(new Runnable() { @Override public void run() { Log.d(TAG, "inserting " + articleArrayList.size() + " repos"); articleDao.insertArticles(articleArrayList); } }); } public void otherFunction(ArrayList
articleArrayList){ // TODO } public DataSource.Factory getAllArticles() { return articleDao.getAllArticles(); }

AppRepository

public class AppRepository {

private static final String TAG = AppRepository.class.getSimpleName();
private static final int DATABASE_PAGE_SIZE = 20;
private Service service;
private LocalCache localCache;
private LiveData> mPagedListLiveData;

public AppRepository(Service service, LocalCache localCache) {
    this.service = service;
    this.localCache = localCache;
}

/**
 * Search - match the query.
 */
public ApiSearchResultObject search(String q){
    Log.d(TAG, "New query: " + q);

    // Get data source factory from the local cache
    DataSource.Factory dataSourceFactory = localCache.getAllArticles();

    // every new query creates a new BoundaryCallback
    // The BoundaryCallback will observe when the user reaches to the edges of
    // the list and update the database with extra data
    ArticleBoundaryCallback boundaryCallback = new ArticleBoundaryCallback(q, service, localCache);

    // Get the paged list
    LiveData data = new LivePagedListBuilder(dataSourceFactory, DATABASE_PAGE_SIZE)
            .setBoundaryCallback(boundaryCallback)
            .build();

    mPagedListLiveData = data;

    ApiSearchResultObject apiSearchResultObject = new ApiSearchResultObject();
    apiSearchResultObject.setArticles(data);

    return apiSearchResultObject;
}

public DataSource.Factory getAllArticles() {
    return localCache.getAllArticles();
}

public void insertAllArticles(ArrayList
articleList) { localCache.insertAllArticles(articleList); } }

视图模型

public class DBArticleListViewModel extends ViewModel {

private AppRepository repository;

// init a mutable live data to listen for queries
private MutableLiveData queryLiveData = new MutableLiveData();

// make the search after each new search item is posted with (searchRepo) using "map"
private LiveData repositoryResult =  Transformations.map(queryLiveData, queryString -> {
    return repository.search(queryString);
});

// constructor, init repo
public DBArticleListViewModel(@NonNull AppRepository repository) {
    this.repository = repository;
}

// get my Articles!!
public LiveData> articlesLiveData = Transformations.switchMap(repositoryResult, object ->
        object.getArticles());

// get teh Network errors!
public LiveData errorsLiveData = Transformations.switchMap(repositoryResult, object ->
        object.getNetworkErrors());


// Search REPO
public final void searchRepo(@NonNull String queryString) {
    this.queryLiveData.postValue(queryString);
}

// LAST Query string used
public final String lastQueryValue() {
    return (String)this.queryLiveData.getValue();
}

活动-从VM观察

 DummyPagedListAdapter articleListAdapter = new DummyPagedListAdapter(this);

    localDBViewModel = ViewModelProviders.of(this, Injection.provideViewModelFactory(this)).get(DBArticleListViewModel.class);

    localDBViewModel.articlesLiveData.observe(this, pagedListLiveData ->{
        Log.d(TAG, "articlesLiveData.observe size: " + pagedListLiveData.size());
        if(pagedListLiveData != null)
            articleListAdapter.submitList(pagedListLiveData);
    });

    recyclerView.setAdapter(articleListAdapter);

适配器

public class DummyPagedListAdapter extends PagedListAdapter {

private final ArticleListActivity mParentActivity;

public DummyPagedListAdapter(ArticleListActivity parentActivity) {
    super(Article.DIFF_CALLBACK);
    mParentActivity = parentActivity;
}

@NonNull
@Override
public ArticleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(mParentActivity).inflate(R.layout.article_list_content, parent, false);
    return new ArticleViewHolder(itemView);
}

@Override
public void onBindViewHolder(@NonNull ArticleViewHolder holder, int position) {
    Article article = getItem(position);

    if (article != null) {
        holder.bindTo(article);
    } else {
        holder.clear();
    }
}
}

DIFF

   public static DiffUtil.ItemCallback
DIFF_CALLBACK = new DiffUtil.ItemCallback
() { @Override public boolean areItemsTheSame(@NonNull Article oldItem, @NonNull Article newItem) { return oldItem.getId() == newItem.getId(); } @Override public boolean areContentsTheSame(@NonNull Article oldItem, @NonNull Article newItem) { return oldItem.getWebUrl() == newItem.getWebUrl(); } };

我真的需要解决这个问题。谢谢!



1> jorjSB..:

是的..我花了一段时间,但我解决了。如我所想,这是一个愚蠢的问题:在适配器用来确定要从观察到的数据集中添加和忽略什么的DIFF_CALLBACK中,我使用的是作为字符串的比较器oldItem.getId()== newItem.getId()! !! 当然,适配器总是在获取“新值”并添加它们。

更正了DiffUtil.ItemCallback

 public static DiffUtil.ItemCallback
DIFF_CALLBACK = new DiffUtil.ItemCallback
() { @Override public boolean areItemsTheSame(@NonNull Article oldItem, @NonNull Article newItem) { return oldItem.getStoreOrder() == newItem.getStoreOrder(); } @Override public boolean areContentsTheSame(@NonNull Article oldItem, @NonNull Article newItem) { return oldItem.getId().equals(newItem.getId()) && oldItem.getWebUrl().equals(newItem.getWebUrl()); } };

我希望这将提醒您始终关注最基本的事情。我为此浪费了很多时间。希望你不会:)


推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • python3 nmap函数简介及使用方法
    本文介绍了python3 nmap函数的简介及使用方法,python-nmap是一个使用nmap进行端口扫描的python库,它可以生成nmap扫描报告,并帮助系统管理员进行自动化扫描任务和生成报告。同时,它也支持nmap脚本输出。文章详细介绍了python-nmap的几个py文件的功能和用途,包括__init__.py、nmap.py和test.py。__init__.py主要导入基本信息,nmap.py用于调用nmap的功能进行扫描,test.py用于测试是否可以利用nmap的扫描功能。 ... [详细]
  • 1.Listener是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时 ... [详细]
  • 【爬虫】关于企业信用信息公示系统加速乐最新反爬虫机制
    ( ̄▽ ̄)~又得半夜修仙了,作为一个爬虫小白,花了3天时间写好的程序,才跑了一个月目标网站就更新了,是有点悲催,还是要只有一天的时间重构。升级后网站的层次结构并没有太多变化,表面上 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
author-avatar
yuguiping123
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有