- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在尝试编写一些代码以使一些可以稍后观看的内容离线。此内容由 json、图像、视频和 pdf 组成:
{
"elements": [
{
"id":"3b4c4f3da8bf9d1527010c5242e037b7",
"type":"media"
},
...
],
"id":"58088318ef0b4832f6c0e70b",
"content": "Hello World"
}
所以基本上我的问题是我在异步网络调用和 Realm 数据库更新之间切换,我不知道如何构建它。
我首先获取上面的 Json 必须将其存储在 Realm 中,然后我为每个元素调用第二个路由以获取 DetailedElement
并将其存储。当元素包含可下载文档时,我必须下载它并将其路径添加为 DetailedElement
的成员。问题是,我无法正确处理线程。
理想情况下,我想要一个带有此签名的方法:
FooBar.prefetch(Context ctx, String id, Callback cb)
我的第一步应该是确保它在非 UI Looper 线程中启动:我不确定该怎么做
public static void Bar(final Context ctx, final String id) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
final Realm realm = Realm.getDefaultInstance();
final Handler handler = new Handler();
MainThingToDownload mainThingToDownload = realm.where(MainThingToDownload.class).equalTo("id", id).findFirst();
if (mainThingToDownload != null) {
processMain(mainThingToDownload, realm, handler);
} else {
Api.getInstance().backendRepresentation.getMainThing(id).enqueue(new CustomRetrofitCallBack<>(null) {
@Override
public void onResponseReceived(final MainThingToDownload mainThingToDownload) {
handler.post(new Runnable() {
@Override
public void run() {
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(mainThingToDownload);
processMain(mainThingToDownload, realm, handler);
}
});
}
});
}
});
}
}
});
}
这是正确的方法吗?保留其线程的 Realm 引用和处理程序引用。然后我总是在我的网络回调中做类似的事情:
handler.post(new Runnable() {
@Override
public void run() {
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
//... add downloaded object to realm or modifies one
}
});
}
});
我的代码有很多不同的错误。大多数时候,我不会在应该使用它的线程上使用 Realm,有时我会使用一个已经关闭的 Realm 实例。
这就是我应该做的吗?谢谢,
我做了什么
一个Program
包含一个Module
列表,每个Module
包含一个Element
列表。
ProgramOfflineManager
public class ProgramOfflineManager extends AbstractOfflineManager {
private final static String TAG = "ModuleOfflineManager";
public ProgramOfflineManager(Context ctx, String id, ErrorDisplayerInterface errorDisplayerInterface) {
super(ctx, id, errorDisplayerInterface);
}
@Override
protected void makeOffline() throws IOException {
super.makeOffline();
ProgramOfflineManager.makeOffline(id, ctx);
}
@Override
protected void removeOffline() {
super.removeOffline();
ProgramOfflineManager.removeOffline(id, ctx);
}
public static void removeOffline(String programId, Context ctx) {
Log.i(TAG, "to be deleted");
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
//To be deleted
final Program program = realm.where(Program.class).equalTo("id", programId).findFirst();
Log.i("renaud", "courseDetailed matching is is not null : (detailed!=null)=>" + (program != null));
if (program != null) {
for (Module module : program.getModules()) {
CourseDetailed courseDetailed = realm.where(CourseDetailed.class).equalTo("id", module.getCourse()).equalTo("downloaded", true).findFirst();
if (courseDetailed != null) {
ModuleOfflineManager.removeOffline(module.getCourse(), ctx);
}
}
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
program.deleteFromRealm();
Log.i(TAG, "course has been deleted");
}
});
}
} finally {
if (realm != null) {
realm.close();
}
realm = null;
}
}
public static void makeOffline(final String programId, final Context ctx) throws IOException {
Api.Service360Interface backend = Api.getInstance().backend;
Response<Program> programResponse = backend.getProgram(programId).execute();
if (programResponse.isSuccessful()) {
final Program program = programResponse.body();
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
program.setDownloaded(true);
realm.copyToRealmOrUpdate(program);
}
});
for (final Module module : program.getModules()) {
long count = realm.where(CourseDetailed.class).equalTo("id", module.getCourse()).equalTo("downloaded", true).count();
if (count == 0) {
ModuleOfflineManager.makeOffline(module.getCourse(), ctx);
}
}
} finally {
if (realm != null) {
realm.close();
}
realm = null;
}
}
}
}
ModuleOfflineManager
public class ModuleOfflineManager extends AbstractOfflineManager {
private final static String TAG = "ModuleOfflineManager";
public ModuleOfflineManager(Context ctx, String id, ErrorDisplayerInterface errorDisplayerInterface) {
super(ctx, id, errorDisplayerInterface);
}
@Override
protected void makeOffline() throws IOException {
super.makeOffline();
ModuleOfflineManager.makeOffline(id, ctx);
}
@Override
protected void removeOffline() {
super.removeOffline();
ModuleOfflineManager.removeOffline(id, ctx);
}
public static void removeOffline(String courseId, Context ctx) {
Log.i(TAG, "to be deleted");
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
//To be deleted
final CourseDetailed detailed = realm.where(CourseDetailed.class).equalTo("id", courseId).findFirst();
Log.i("renaud", "courseDetailed matching is is not null : (detailed!=null)=>" + (detailed != null));
if (detailed != null) {
for (Element element : detailed.getElements()) {
Log.i(TAG, "next Element to suppress : " + element.getId());
final CourseElement courseElement = realm.where(CourseElement.class).equalTo("id", element.getId()).findFirst();
if (courseElement.getCollection() != null && courseElement.getCollection() == PostCollectionType.MEDIAS) {
Log.i(TAG, "it's a Media, erasing from db");
MediaDownloadUtils.eraseMedia(ctx, courseElement, realm);
}
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
courseElement.deleteFromRealm();
Log.i(TAG, "element has been deleted");
}
});
}
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
detailed.deleteFromRealm();
Log.i(TAG, "course has been deleted");
}
});
}
} finally {
if (realm != null) {
realm.close();
}
realm = null;
}
}
public static void makeOffline(final String courseId, final Context ctx) throws IOException {
Api.Service360Interface backend = Api.getInstance().backend;
Response<CourseDetailed> response = backend.getCourse(courseId).execute();
if (response.isSuccessful()) {
final CourseDetailed courseDetailedResponse = response.body();
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
courseDetailedResponse.saveEnums();
courseDetailedResponse.setDownloaded(true);
realm.copyToRealmOrUpdate(courseDetailedResponse);
}
});
for (final Element element : courseDetailedResponse.getElements()) {
Call<CourseElement> call = Api.getInstance().getCourseElement(element.getCollection(), element.getId(), courseId);
Response<CourseElement> courseElementResponse = call.execute();
if (courseElementResponse.isSuccessful()) {
final CourseElement courseElement = courseElementResponse.body();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
courseElement.setCourseElementType(CourseElementTypes.valueOf(element.getCollection()));
courseElement.saveEnums();
courseElement.setDownloaded(true);
realm.copyToRealmOrUpdate(courseElement);
MediaDownloadUtils.prefechMedia(ctx, courseElement);
}
});
}
}
} finally {
if (realm != null) {
realm.close();
}
realm = null;
}
}
}
}
抽象离线管理器
public abstract class AbstractOfflineManager implements OfflineManagerInterface {
private final static String TAG = "AbstractOfflineManager";
final protected Context ctx;
final protected String id;
final protected ErrorDisplayerInterface errorDisplayerInterface;
protected boolean status;
public AbstractOfflineManager(Context ctx, String id, ErrorDisplayerInterface errorDisplayerInterface) {
this.ctx = ctx;
this.id = id;
this.errorDisplayerInterface = errorDisplayerInterface;
}
protected void makeOffline() throws IOException {
//implementations in children
}
protected void removeOffline() {
//implementations in children
}
@Override
public CompoundButton.OnCheckedChangeListener getClickListener() {
return new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, final boolean isChecked) {
Log.i(TAG, "clic ! isChecked : " + isChecked);
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
status = isChecked;
if (isChecked) {
try {
makeOffline();
} catch (IOException e) {
e.printStackTrace();
errorDisplayerInterface.popError(null, e);
}
} else {
removeOffline();
}
}
}).start();
}
};
} }
现在我将创建一个 ElementOfflineManager
最佳答案
Is it the right approach ? keeping the realm reference and the handler reference for its thread.
没有必要。只要您关闭实例,Realm 就可以在任何后台线程上使用。
Realm 已经管理了 UI 线程及其自动更新的处理程序,因此您无需自己手动执行此操作。
你把一个相当简单的问题复杂化了。您应该让 Retrofit 在后台线程上同步执行,而不是在 UI 线程上执行。
像这样:
protected ExecutorService executor = Executors.newSingleThreadExecutor();
//...
public static void bar(final Context ctx, final String id) {
MainThingToDownload mainThingToDownload = mRealm.where(MainThingToDownload.class)
.equalTo("id", id)
.findFirst();
// assuming there is a UI thread Realm
if (mainThingToDownload != null) {
processMain(mainThingToDownload);
} else {
executor.execute(new Runnable() {
@Override
public void run() {
Response<MainThingToDownload> response = Api.getInstance()
.backendRepresentation
.getMainThing(id)
.execute();
MainThingToDownload mainThingToDownload = response.body();
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.insertOrUpdate(mainThingToDownload);
}
}
} finally {
if(realm != null) {
realm.close();
}
}
}
});
}
有关更多一般信息,请查看 the guide on the basics of Realm , 或 this very simple gist
(这里是要点:
public class NewsActivity extends AppCompatActivity {
// ...
private RealmChangeListener<RealmResults<NewsPost>> realmChangeListener;
private RealmResults<NewsPost> listenerSet;
private long postId;
private Realm realm;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
Injector.get().inject(this);
postId = getIntent().getLongExtra("postId");
setContentView(R.layout.activity_news);
ButterKnife.bind(this);
realm = RealmManager.getRealm();
realmChangeListener = new RealmChangeListener<RealmResults<NewsPost>>() {
@Override
public void onChange(RealmResults<NewsPost> element) {
NewsPost newsPost = realm.where(NewsPost.class)
.equalTo(NewsPostFields.ID, postId)
.findFirst();
if(newsPost != null) { // if news post was downloaded on background thread, initalize view
initView(newsPost);
}
}
};
listenerSet = realm.where(NewsPost.class)
.findAll();
listenerSet.addChangeListener(realmChangeListener); // listen to changes in `NewsPost` table
NewsPost newsPost = realm.where(NewsPost.class)
.equalTo(NewsPostFields.ID, postId)
.findFirst();
if(newsPost == null) {
// download news post if not available
getNewsPostInteractor.getNewsPost(postId);
} else {
initView(newsPost);
}
}
private void initView(NewsPost newsPost) {
// set views
}
}
)
哦,还有you should close any Realm instance that you open with getDefaultInstance()
.我看得出你没有那样做。
关于android - Realm 实例和多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40376287/
我最近在/ drawable中添加了一些.gifs,以便可以将它们与按钮一起使用。这个工作正常(没有错误)。现在,当我重建/运行我的应用程序时,出现以下错误: Error: Gradle: Execu
Android 中有返回内部存储数据路径的方法吗? 我有 2 部 Android 智能手机(Samsung s2 和 s7 edge),我在其中安装了一个应用程序。我想使用位于这条路径中的 sqlit
这个问题在这里已经有了答案: What's the difference between "?android:" and "@android:" in an android layout xml f
我只想知道 android 开发手机、android 普通手机和 android root 手机之间的实际区别。 我们不能从实体店或除 android marketplace 以外的其他地方购买开发手
自Gradle更新以来,我正在努力使这个项目达到标准。这是一个团队项目,它使用的是android-apt插件。我已经进行了必要的语法更改(编译->实现和apt->注释处理器),但是编译器仍在告诉我存在
我是android和kotlin的新手,所以请原谅要解决的一个非常简单的问题! 我已经使用导航体系结构组件创建了一个基本应用程序,使用了底部的导航栏和三个导航选项。每个导航选项都指向一个专用片段,该片
我目前正在使用 Facebook official SDK for Android . 我现在正在使用高级示例应用程序,但我不知道如何让它获取应用程序墙/流/状态而不是登录的用户。 这可能吗?在那种情
我在下载文件时遇到问题, 我可以在模拟器中下载文件,但无法在手机上使用。我已经定义了上网和写入 SD 卡的权限。 我在服务器上有一个 doc 文件,如果用户单击下载。它下载文件。这在模拟器中工作正常但
这个问题在这里已经有了答案: What is the difference between gravity and layout_gravity in Android? (22 个答案) 关闭 9
任何人都可以告诉我什么是 android 缓存和应用程序缓存,因为当我们谈论缓存清理应用程序时,它的作用是,缓存清理概念是清理应用程序缓存还是像内存管理一样主存储、RAM、缓存是不同的并且据我所知,缓
假设应用程序 Foo 和 Eggs 在同一台 Android 设备上。任一应用程序都可以获取设备上所有应用程序的列表。一个应用程序是否有可能知道另一个应用程序是否已经运行以及运行了多长时间? 最佳答案
我有点困惑,我只看到了从 android 到 pc 或者从 android 到 pc 的例子。我需要制作一个从两部手机 (android) 连接的 android 应用程序进行视频聊天。我在想,我知道
用于使用 Android 以编程方式锁定屏幕。我从 Stackoverflow 之前关于此的问题中得到了一些好主意,并且我做得很好,但是当我运行该代码时,没有异常和错误。而且,屏幕没有锁定。请在这段代
文档说: android:layout_alignParentStart If true, makes the start edge of this view match the start edge
我不知道这两个属性和高度之间的区别。 以一个TextView为例,如果我将它的layout_width设置为wrap_content,并将它的width设置为50 dip,会发生什么情况? 最佳答案
这两个属性有什么关系?如果我有 android:noHistory="true",那么有 android:finishOnTaskLaunch="true" 有什么意义吗? 最佳答案 假设您的应用中有
我是新手,正在尝试理解以下 XML 代码: 查看 developer.android.com 上的文档,它说“starStyle”是 R.attr 中的常量, public static final
在下面的代码中,为什么当我设置时单选按钮的外观会发生变化 android:layout_width="fill_parent" 和 android:width="fill_parent" 我说的是
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
假设我有一个函数 fun myFunction(name:String, email:String){},当我调用这个函数时 myFunction('Ali', 'ali@test.com ') 如何
我是一名优秀的程序员,十分优秀!