[英]Update ListView asynchronously using Realm
當我將數據從領域數據庫填充到列表視圖時,我的應用程序掛起了一段時間。
所以我計划異步使用它,因此在收集數據的同時,我在這里顯示了一個加載對話框,即代碼。
已經無法在我的情況下實施此問題 。
private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
ProgressDialog progressDialog;
@Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
@Override
protected RealmResults doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
realm = realm.getDefaultInstance();
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
sscresult = query.findAll(); //error 1
return sscresult;
}
@Override
protected void onPostExecute(RealmResults r) {
progressDialog.dismiss();
list.setAdapter(new MyAdapter(sscresult)); //error 2
realm.close();
}
}
好的,所以有兩個問題,如果任何人都可以解決,我的應用程序將沒有錯誤
這只能在UI線程中運行
來自錯誤線程的領域訪問。 只能在創建對象的線程上訪問領域對象。
我無法解決此問題,請幫助
您可以使用Realm中的異步查詢API在后台線程上對查詢進行評估。
private OrderedRealmCollectionChangeListener<RealmResults<User> callback = new OrderedRealmCollectionChangeListener<>() {
@Override
public void onChange(RealmResults<User> results, OrderedCollectionChangeSet changeSet) {
if (changeSet == null) {
// The first time async returns with an null changeSet.
} else {
// Called on every future update.
}
}
};
private RealmResults<User> result;
public void onStart() {
result = realm.where(User.class).findAllAsync();
result.addChangeListener(callback);
}
但是,如果將RealmResults
提供給RealmRecyclerViewAdapter
,則這是自動的。
PS沒有關閉doInBackground()
Realm
實例, doInBackground()
是S類可怕的錯誤。 請在非循環后台線程上關閉您的Realm實例。
具體來說如下:
// private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
//
// ProgressDialog progressDialog;
// @Override
// protected void onPreExecute() {
// // start loading animation maybe?
// progressDialog = ProgressDialog.show(DictionarySscWords.this,
// "ProgressDialog",
// "Loading all words!");
// }
//
// @Override
// protected RealmResults doInBackground(String... params) {
// RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
// Realm.setDefaultConfiguration(realmConfig);
// realm = realm.getDefaultInstance();
// RealmQuery<Word> query = realm.where(Word.class);
//
// for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
// if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
//
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
// } else {
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
// .or();
//
// }
//
// }
// sscresult = query.findAll(); //error 1
// return sscresult;
//
// }
//
// @Override
// protected void onPostExecute(RealmResults r) {
// progressDialog.dismiss();
// list.setAdapter(new MyAdapter(sscresult)); //error 2
// realm.close();
// }
//}
和
public class MyActivity extends AppCompatActivity {
private RealmResults<Word> words;
private Realm realm;
private WordAdapter wordAdapter;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.my_activity);
ButterKnife.bind(this);
realm = Realm.getDefaultInstance();
words_for_ssc = ...
RealmQuery<Word> query = realm.where(Word.class);
String[] array = words_for_ssc[Integer.parseInt(params[0])];
for (int i = 0; i < array.length; i++) {
query = query.equalTo("word", array[i]);
if (i != array.length - 1) {
query = query.or();
}
}
words = query.findAllSortedAsync("word");
wordAdapter = new WordAdapter(words);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(wordAdapter);
}
@Override
public void onDestroy() {
super.onDestroy();
realm.close();
realm = null;
}
}
public class WordAdapter extends RealmRecyclerViewAdapter<Word, WordViewHolder> {
public class WordAdapter(OrderedRealmCollection<Word> words) {
super(words, true);
}
@Override
public WordViewHolder onCreateViewHolder(...) {
...
}
@Override
public void onBindViewHolder(WordViewHolder holder, int position) {
holder.bind(getData().get(position));
}
public static class WordViewHolder extends RecyclerView.ViewHolder {
public WordViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
public void bind(Word word) {
...
}
}
}
我認為可以在不編寫很多代碼的情況下編寫更干凈的解決方案。 在這種情況下,領域的所有操作都發生在doInBackground
內部的后台線程上。 realm
實例也在創建它的線程上關閉。
現在,我基本上要做的是,我從realm.copyFromRealm(sscresult)
RealmResult
提取了Words
列表的深層副本,該副本與realm
完全分離,可以在任何線程內移動和修改。 現在,所有這些對象都不受領域限制,可以在onPostExecute
使用,而無需擔心。 您唯一需要修改的是MyAdapter
構造函數,它不需要RealmResult而是一個Words
列表,正是您所需要的,並且可以像RealmResult
一樣進行迭代。
這種方法的唯一缺點是Words
列表不會自動同步,因為它們是分離的,並且如果它們在Realm中從其他位置更改,其值也不會自動更改。 但我很確定,它不會打擾您。
我還要附上realm.copyFromRealm()
的官方參考,它在這里 。
private class YourAsyncTask extends AsyncTask<String, String, List<Word>> {
ProgressDialog progressDialog;
@Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
@Override
protected List<Word> doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
try(realm = realm.getDefaultInstance()) {
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
// Here's the sort. Use findAllSorted instead.
// You can change Sort.ASCENDING to Sort.DESCENDING to reverse
// the order.
sscresult = query.findAllSorted("word", Sort.ASCENDING);
// This is where the magic happens. realm.copyFromRealm() takes
// a RealmResult and essentially returns a deep copy of the
// list that it contains. The elements of this list is however
// completely detached from realm and is not monitored by realm
// for changes. Thus this list of values is free to move around
// inside any thread.
ArrayList<Word> safeWords = realm.copyFromRealm(sscresult);
realm.close();
return safeWords;
}
}
@Override
protected void onPostExecute(List<Word> words) {
progressDialog.dismiss();
// Please note here MyAdaptor constructor will now take the
// list of words directly and not RealmResults so you slightly
// modify the MyAdapter constructor.
list.setAdapter(new MyAdapter(words));
}
}
希望能幫助到你!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.