- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有一个带有 ListView 的 fragment 。
在 onPause() 中,我将 ListView 的 Y 滚动位置保存在 ContentProvider 中。
onResume 或 onActivityCreated 上的同一 fragment 使用加载器从内容提供者获取 y 滚动位置并恢复滚动位置。
如果我退出 Activity/fragment 并返回到它,这将起作用, ListView 将返回到其上次打开的位置,因为它在 onPause 中被保存到内容提供者。所以代码 100% 没问题。
不好的是数据在轮换。 onPause 可以很好地保存,但是 onCreateActivity 之后的加载会导致检索旧数据,即保存在 onPause 之前的数据。这会导致 ListView 返回到他们第一次打开应用程序时的旧位置,而不是 ListView 在旋转之前的位置。
这似乎是一个明显的竞争条件,即在 onPause 期间向内容提供者的保存未在 onPause 中完成,导致在旋转后加载旧数据。
所以我手机上的旋转看起来像这样
01:31:33.026: ThreadViewerFragment.java(235):onPause Saved(position:Yposition): 59:-74
01:31:33.256: ThreadViewerFragment.java(194):onActivityCreated
01:31:33.266: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 62:-149 //initial load is of old values
01:31:33.266: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 62:-149
01:31:33.596: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 59:-74 //this is loaded due to notification by the save in onPause which is supposed to be finished before recreating the new fragment???
因此顺序看起来不错(在 Activity/fragment 流方面看起来不像竞争条件)但很明显,它加载了旧值而不是刚刚保存的值 59:-74。
我不是在变通之后,我知道如何使用 saveInstanceState 等。但是为什么我应该加倍我的代码,有没有办法强制内容提供者以原子方式运行(我认为它已经是?)
编辑:添加代码并更好地细化问题,因为我仍然不满意我们是否更接近理解 contentprovider 调用是否在执行时阻塞和/或这些调用是否是原子的,或者它是否只是对内容提供者和加载器。
在 onPause 中,我保存了产品列表的 Y 位置
@Override
public void onPause() {
super.onPause();
Utils.logv("onPause Saved position: " + mLastRead + ", " + mYPos);
ContentValues contentValues = new ContentValues();
contentValues.put(ProductsContract.Products.Y_POS, mYpos);
int updateCount = getActivity().getContentResolver().update(
Uri.parse(ProductsContract.Products.CONTENT_URI + "/" + mId),
contentValues, null, null);
}
我的理解是调用update应该是阻塞调用,发生在fragment被销毁之前和新fragment创建之前处理轮换
在简历中,我启动了装载机
public void onResume() {
super.onResume();
getLoaderManager().initLoader(PRODUCTS_LOADER_ID, null, this);
}
在我的加载程序中,我得到了游标,它在旋转后可靠地拥有旧数据,但在任何其他情况下都很好
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
if(cursor.moveToFirst()){
mYpos = cursor.getInt(cursor.getColumnIndex(ProductsContract.Products.Y_POS));
Utils.logv("loader: " + mYpos);
}
}
所以重申一下,在轮换之后,加载程序将始终如一地传送旧数据。
我在想,也许是加载器过时了,而不是内容提供者本身?光标在旋转后被保存和恢复,即使它是陈旧的?
最佳答案
It seems like an obvious race condition that the save to the content provider is not completed in the onPause before it is loaded after the rotate.
假设上面的陈述是正确的:
通常内容提供者速度很快,应该不会花那么多时间。但是,当 ContetnProvider
由 SQLite
支持时,将数据插入数据库需要时间是可以理解的。延迟时间取决于数据量和设备硬件。
但是,这种方法的问题在于,用户只是旋转屏幕并且真的不喜欢等待,看到数据正在一个接一个地加载。 旋转应该很快非常快。
这条路的替代方案是,
onPause
完成任务(这将阻止下次创建 UI,这是非常非常糟糕的主意)此路径上的另一种选择是,创建一个仅用于处理轮换情况的内存缓存。这意味着每次查找数据时,首先尝试在缓存中找到它,如果没有,则尝试从 ContentProvider
加载。您可以对缓存的键使用相同的内容 URI。并且,对于写入,首先在缓存中写入,然后在提供程序中写入。
ContentProvider
提供了一些很大的好处,这一点毋庸置疑。如果您需要 ContentProvider
,您应该使用它。但是,为了处理轮换,您可以考虑其他选择。而且,解决方案的方法是将内容转储到文件中并读回。 SharedPreferences
或典型的文件 IO 现在就在我的脑海中。我想这是它们存在的一个很好的理由。
最后,出于好奇,您是否尝试过加载 fragment 的数据 onResume
状态?并且,希望 setRetainInstance(boolean)
未在您的代码中的某处设置。
编辑,
据我所知,ContentProvider 不提供任何原子性或线程安全性。来自 Android 文档,
the methods query(), insert(), delete(), update(), and getType()—are called
from a pool of threads in the content provider's process, not the UI thread
for the process. Because these methods might be called from any number of
threads at the same time, they too must be implemented to be thread-safe.
如果我能看到你的代码,我可能会给你一个更好的答案。
关于android - ContentProvider 调用原子? onPause保存,加载OnActivityCreated,旧数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16696085/
有没有办法用连词创建原子 if ?也就是说,我可以以某种方式在 C 中自动测试 if(A && B) 吗?如果它在第一个连接处短路,那么没问题,但如果没有短路,则在检查 B 时,A 可能已更改。有什么
我有很多 fork 的过程。子进程做很多事情和另一个系统调用。 当任何子进程从系统调用中获取错误时,它会将错误描述打印到 stderr 并将 SIGUSR1 发送到组长(主要父进程)。 SIGUSR1
阅读 boost::atomic 上的文档和 std::atomic 让我感到困惑的是 atomic 是否接口(interface)应该支持非平凡类型? 也就是说,给定一个只能通过将读/写包含在一个完
我有一个命令,可以将叠加图像放在视频上。 之后,我调整输出大小以适合某些尺寸。 通常一切正常,但有时且仅在某台台式计算机上,当第二次精化开始时,命令返回错误:moov atom not found 让
我最近发现当 LANG 设置为 C.utf8 时,X11 原子 WM_NAME 未在 Swing JFrame 中设置。但为 LANG 的其他值设置。这发生在带有 OpenJDK 11.0.9 的 L
我目前正在使用blackmagic的prorecorder录制视频。我使用 ffmpeg 将视频即时转码为 mp4 视频容器。持续时间未知,因为我正在对 prorecorder 输出到命名管道的 .t
这里真的有人使用 atom 来处理 git 提交消息吗?我想但我遇到了这个问题并且一直坚持使用 git commit -m '....' 。当我尝试使用 atom 时,它会打开 atom,我几乎立即从
考虑: void foo() { std::vector> foo(10); ... } foo 的内容现在有效吗?或者我是否需要显式循环并初始化它们?我检查过 Godbolt,看起来不错,但
在official FAQ我阅读的 Memcached: “发送到 memcached 的所有单独命令都是绝对原子的。” 然而,当涉及到 get_multi 和 set_multi 时,我仍然不清楚。
在测试程序的可扩展性时,我遇到了必须将 memcpy 操作设置为原子操作的情况。我必须将 64 字节的数据从一个位置复制到另一个位置。 我遇到了一种解决方案,即使用旋转变量: struct recor
我对 C++ 原子变量感到困惑。如果我有一个原子 x,我想在一个线程中递增并在另一个线程中读取,我可以执行++x 还是必须执行 x.atomic_fetch_add(1)。在读者线程中,我可以做类似
跟进自 Multiple assignment in one line ,我很想知道这对原子数据类型是如何工作的,特别是 bool 类型的例子。 给定: class foo { std::at
我想创建一个版本控制系统,并且对版本号为 1 的新条目的查询如下所示: ID 和修订号组合起来就是主键。 insert into contentfile (id, name, revision, ac
我在 iOS 项目中有下一个独立的测试片段: /// ... std::atomic_bool ab; ab.store(true); bool expected = false; while (!a
我了解如何使用条件变量(此构造的名称很糟糕,IMO,因为 cv 对象既不是变量也不表示条件)。所以我有一对线程,canonically使用 Boost.Thread 设置为: bool awake =
因此,对于最终项目,我尝试制作一款包含三种不同 meteor 的游戏;铜牌、银牌和金牌。虽然青铜阵列在Setup()中工作正常,但银色和金色 meteor 由于某种未知原因而高速移动。 functio
第一个问题,为什么不在 atomic_compare_exchange_weak 操作的参数中应用后缀求值 (++)?运算前后a的值相同。然而,当在 printf() 中使用时,正如预期的那样,该值会
我正在尝试使用 OpenMP 对已经矢量化的代码进行内部函数并行化,但问题是我使用一个 XMM 寄存器作为外部“变量”,我会在每个循环中递增。现在我正在使用 shared 子句 __m128d xmm
clojure“atom”的文档指出 - "Changes to atoms are always free of race conditions." 但是,竞争条件不仅根据更改定义,而且在不同线程中
我一直在研究原子引用计数的实现。 库之间的大多数操作都非常一致,但我在“减少引用计数”操作中发现了惊人的多样性。 (请注意,通常情况下,shared 和 weak decref 之间的唯一区别是调用了
我是一名优秀的程序员,十分优秀!