领域大型RealmResults在修改数据时阻止UI线程

时间:2016-10-24 14:31:02

标签: android realm

我一直在尝试使用大型数据集来测试Realm的性能。它似乎执行非常好的插入和查询导致中等结果集大小但是只要结果集很大,它就会开始影响主线程,即使实际写入正在运行异步。我写了一个测试活动,显示下面的问题。几点说明:

  1. 参加者是主键为“name”且索引整数字段为“age”的模型。
  2. 该视图有一个显示计数的文本字段,一个在点击时调用reloadData的按钮,以及一个交互式元素(我使用滑块)来查看使用它时跳过的帧。
  3. 如果您更改列表的查询,以便它导致较小的结果集(而不是更少,则更改为equalsTo),那么问题就会消失。
  4. 这是一个错误还是我做错了什么?

    package com.test.ui;
    
    import android.content.Context;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.test.R;
    import com.test.model.Attendee;
    
    import io.realm.OrderedRealmCollection;
    import io.realm.Realm;
    import io.realm.RealmAsyncTask;
    import io.realm.RealmRecyclerViewAdapter;
    import io.realm.RealmResults;
    
    public class LoginActivity extends AppCompatActivity {
    
        private static final int RECORD_COUNT = 200000;
        private static final int TRANSACTION_SIZE = 1000;
        private RealmAsyncTask mTask = null;
        private RecyclerView mAttendeeList;
        private TextView mCountText;
        private Button mButton;
        private Handler handler;
        private Realm mRealm;
        private RealmResults<Attendee> mActualList;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    
            mRealm = Realm.getDefaultInstance();
    
            mCountText = (TextView) findViewById(R.id.count_text);
            mButton = (Button) findViewById(R.id.button);
            handler = new Handler(Looper.getMainLooper());
    
            setCountText((int) mRealm.where(Attendee.class).count());
            mActualList = mRealm.where(Attendee.class).lessThan("age", 20).findAllAsync();
    
            mRealm.executeTransactionAsync(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    realm.deleteAll();
                    setCountText(0);
                }
            }, new Realm.Transaction.OnSuccess() {
                @Override
                public void onSuccess() {
                    mButton.setEnabled(true);
                }
            }, new Realm.Transaction.OnError() {
                @Override
                public void onError(Throwable error) {
                    String text = "Error deleting";
                    Log.e("ANRTEST", text, error);
                    Toast.makeText(LoginActivity.this, text, Toast.LENGTH_LONG).show();
                }
            });
    
        }
    
        private void setCountText(int size) {
            mCountText.setText(String.format("Count: %s", size));
        }
    
        @Override
        protected void onDestroy() {
            mActualList = null;
            if(mTask != null && !mTask.isCancelled()) {
                mTask.cancel();
                mTask = null;
            }
    
            if(mRealm != null && !mRealm.isClosed()) {
                mRealm.close();
            }
            super.onDestroy();
        }
    
        public void loadData(final TimerUtil t) {
    
            Realm.Transaction.OnError onError = new Realm.Transaction.OnError() {
                @Override
                public void onError(Throwable error) {
                    mTask = null;
                    Toast.makeText(LoginActivity.this, "Finished should show now", Toast.LENGTH_LONG).show();
                }
            };
            Realm.Transaction.OnSuccess onSuccess = new Realm.Transaction.OnSuccess() {
                @Override
                public void onSuccess() {
                    mTask = null;
                    int count = (int) mRealm.where(Attendee.class).count();
                    if (count >= RECORD_COUNT) {
                        Log.v("ANRTEST", String.format("Finished in %s seconds", t.currentElapsed() / 1000));
                        mButton.setEnabled(false);
                    } else {
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                loadData(t);
                            }
                        }, 300);
                    }
                    setCountText(count);
                }
            };
    
            mTask = mRealm.executeTransactionAsync(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    int innerStart = (int) realm.where(Attendee.class).count();
                    int i = 0;
                    while (i < TRANSACTION_SIZE && i + innerStart < RECORD_COUNT) {
                        Attendee attendee = new Attendee();
                        int innerValue = innerStart + i;
                        attendee.name = "name " + (innerValue + 1);
    
                        attendee.age = innerValue % 50;
                        realm.insert(attendee);
                        i++;
                    }
    
                    Log.v("ANRTEST", String.format("Checkpoint %s (%s seconds)", Math.min(innerStart + i, RECORD_COUNT), t.currentElapsed() / 1000));
                }
            }, onSuccess, onError);
        }
    
    
    
        public void reloadData(View view) {
    
            //Setup start of process
            mButton.setEnabled(false);
    
    
            final TimerUtil t = TimerUtil.start();
    
    
           loadData(t);
    
    
        }
    
        public static class TimerUtil {
            private final long mStartTime;
    
            public TimerUtil(long startTime) {
                mStartTime = startTime;
            }
    
            public static TimerUtil start() {
                return new TimerUtil(System.currentTimeMillis());
            }
    
            public long currentElapsed() {
                return System.currentTimeMillis() - mStartTime;
            }
        }
    
    
    }
    

0 个答案:

没有答案