gpt4 book ai didi

android - Realm 实例和多线程

转载 作者:搜寻专家 更新时间:2023-11-01 09:40:06 25 4
gpt4 key购买 nike

我正在尝试编写一些代码以使一些可以稍后观看的内容离线。此内容由 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com