簡體   English   中英

使用Realm異步更新ListView

[英]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();
    }
}

好的,所以有兩個問題,如果任何人都可以解決,我的應用程序將沒有錯誤

  1. 如果我嘗試運行list.setAdapter(new MyAdapter(sscresult)); 在后台進程中的錯誤是:

這只能在UI線程中運行

  1. 如果嘗試在postExecute中運行,則錯誤為:-

來自錯誤線程的領域訪問。 只能在創建對象的線程上訪問領域對象。

我無法解決此問題,請幫助

您可以使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM