如何解决"Realm access from incorrect thread. Realm objects can only be accessed on the thread they were



我正在尝试为我的应用程序制作应用程序小部件,并在应用程序小部件中显示收藏夹列表。但是,它显示错误:

"来自不正确线程的领域访问。领域对象只能是 在创建它们的线程上访问。

FATAL EXCEPTION: Binder:3017_3
                                                                               Process: com.santossingh.capstoneproject, PID: 3017
                                                                               java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
                                                                                   at io.realm.BaseRealm.checkIfValid(BaseRealm.java:353)
                                                                                   at io.realm.RealmResults.isLoaded(RealmResults.java:88)
                                                                                   at io.realm.OrderedRealmCollectionImpl.size(OrderedRealmCollectionImpl.java:303)
                                                                                   at io.realm.RealmResults.size(RealmResults.java:53)
                                                                                   at com.santossingh.capstoneproject.Widget.ListProvider.getCount(ListProvider.java:57)
                                                                                   at android.widget.RemoteViewsService$RemoteViewsFactoryAdapter.getCount(RemoteViewsService.java:154)
                                                                                   at com.android.internal.widget.IRemoteViewsFactory$Stub.onTransact(IRemoteViewsFactory.java:75)
                                                                                   at android.os.Binder.execTransact(Binder.java:565)
03-31 20:32:01.058 1298-1458/? E/SurfaceFlinger: ro.sf.lcd_density must be defined as a build property

如果您知道它,请给我一个关于将数据访问到其他活动中的清晰示例,或者如何调用创建领域数据库的特定线程。

1- 配置活动

public class ConfigActivity extends AppCompatActivity {
    private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    Realm realm;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_config);
        Realm.init(this);
        RealmConfiguration config = new RealmConfiguration.Builder()
                .deleteRealmIfMigrationNeeded()
                .build();
        realm=Realm.getInstance(config);
        assignAppWidgetId();
        startWidget();
    }
    /**
     * Widget configuration activity,always receives appwidget Id appWidget Id =
     * unique id that identifies your widget analogy : same as setting view id
     * via @+id/viewname on layout but appwidget id is assigned by the system
     * itself
     */
    private void assignAppWidgetId() {
        Bundle extras = getIntent().getExtras();
        if (extras != null)
            appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
    }
    /**
     * This method right now displays the widget and starts a Service to fetch
     * remote data from Server
     */
    private void startWidget() {
        // this intent is essential to show the widget
        // if this intent is not included,you can't show
        // widget on homescreen
        Intent intent = new Intent();
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        setResult(Activity.RESULT_OK, intent);
        // start your service
        // to fetch data from web
        Intent serviceIntent = new Intent(this, ListProvider.class);
        serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        startService(serviceIntent);
        // finish this activity
        this.finish();
    }

2- 列表提供程序类

public class ListProvider implements RemoteViewsService.RemoteViewsFactory {
    private MyHandlerThread mHandlerThread=new MyHandlerThread();
    private Context context = null;
    private int appWidgetId;
    RealmResults<FavoriteBooks> booksList;
    RealmConfiguration config;
    public ListProvider(Context context, Intent intent) {
        this.context = context;
        appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
        getDataFromRealm(context);
    }
    @Override
    public void onCreate() {
    }
    @Override
    public void onDataSetChanged() {
        getDataFromRealm(context);
    }
    @Override
    public void onDestroy() {
    }
    @Override
    public int getCount() {
        return booksList.size();
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public RemoteViews getViewAt(final int position) {
        final Lock lock = new Lock();
        final RemoteViews[] result = {null};
        mHandlerThread.getHandler().post(new Runnable() {
            @Override
            public void run() {
                // You can safely access results here.
                result[0] = new RemoteViews(context.getPackageName(), R.layout.widget_item);
                if (booksList!=null) {
                    FavoriteBooks book = booksList.get(position);
                    result[0].setTextViewText(R.id.widgetText, book.getTitle());
                }
                lock.unlock();
            }
        });
        try {
            lock.lock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result[0];
    }
    @Override
    public RemoteViews getLoadingView() {
        return null;
    }
    @Override
    public int getViewTypeCount() {
        return 0;
    }
    //------------
    public class Lock {
        private boolean isLocked;
        public synchronized void lock() throws InterruptedException {
            isLocked = true;
            while (isLocked) {
                wait();
            }
        }
        public synchronized void unlock() {
            isLocked = false;
            notify();
        }
    }
    public class MyHandlerThread extends HandlerThread {
        private Handler mHandler;
        public MyHandlerThread() {
            super("MY_HANDLER_THREAD");
            start();
            mHandler = new Handler(getLooper());
        }
        public Handler getHandler() {
            return mHandler;
        }
    }
    private void getDataFromRealm(final Context context) {
        final Lock lock = new Lock();
        mHandlerThread.getHandler().post(new Runnable() {
            @Override
            public void run() {
                Realm.init(context);
                config = new RealmConfiguration.Builder()
                        .name("favorite1.realm")
                        .schemaVersion(1)
                        .deleteRealmIfMigrationNeeded()
                        .build();
                Realm realm = Realm.getInstance(config);
                booksList = realm.where(FavoriteBooks.class).findAll();
                lock.unlock();
            }
        });
        try {
            lock.lock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3-小部件服务类

public class WidgetService extends RemoteViewsService {
/*
* So pretty simple just defining the Adapter of the listview
* here Adapter is ListProvider
* */
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        int appWidgetId = intent.getIntExtra(
                AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
        // call and return listprovider class
        return (new ListProvider(this.getApplicationContext(), intent));
    }
}

4-小部件提供程序类

public class WidgetProvider extends AppWidgetProvider {
    public final static String DATA_FETCHED="com.santossingh.capstoneproject.DATA_FETCHED";
    @Override
    public void onUpdate(Context context, AppWidgetManager
            appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;
        for (int i = 0; i < N; ++i) {
            RemoteViews remoteViews = updateAppWidget(context,
                    appWidgetIds[i]);
            appWidgetManager.updateAppWidget(appWidgetIds[i],
                    remoteViews);
        }
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }
    private RemoteViews updateAppWidget(Context context, int appWidgetId) {
        //which layout to show on widget
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
        //RemoteViews Service needed to provide adapter for ListView
        Intent svcIntent = new Intent(context, WidgetService.class);
        //passing app widget id to that RemoteViews Service
        svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        //setting a unique Uri to the intent
        //don't know its purpose to me right now
        svcIntent.setData(Uri.parse(
                svcIntent.toUri(Intent.URI_INTENT_SCHEME)));
        //setting adapter to gridView of the widget
        remoteViews.setRemoteAdapter(appWidgetId, R.id.gridViewWidget,
                svcIntent);
        //setting an empty view in case of no data
        remoteViews.setEmptyView(R.id.gridViewWidget, R.id.emptyTextViewWidget);
        return remoteViews;
    }
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        if (intent.getAction().equals(DATA_FETCHED)) {
            int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
            RemoteViews remoteViews = updateAppWidget(context, appWidgetId);
            appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
        }
    }
}

5-远程获取服务类

public class RemoteFetchService extends Service {
    private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
    /**
     * Retrieve appwidget id from intent it is needed to update widget later
     * initialize our AQuery class
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID))
            appWidgetId = intent.getIntExtra(
                    AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
        populateWidget();
        return super.onStartCommand(intent, flags, startId);
    }
    /**
     * Method which sends broadcast to WidgetProvider
     * so that widget is notified to do necessary action
     * and here action == WidgetProvider.DATA_FETCHED
     */
    private void populateWidget() {
        Intent widgetUpdateIntent = new Intent();
        widgetUpdateIntent.setAction(WidgetProvider.DATA_FETCHED);
        widgetUpdateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                appWidgetId);
        sendBroadcast(widgetUpdateIntent);
        this.stopSelf();
    }

6-收藏书类扩展了领域对象

public class FavoriteBooks extends RealmObject {
    @PrimaryKey
    private String id;
    private String title;
    private String author;
    private String buyLink;
    private String image;
    private String price;
    private String publishedDate;
    private String reviewLink;
    private String description;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getBuyLink() {
        return buyLink;
    }
    public void setBuyLink(String buyLink) {
        this.buyLink = buyLink;
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image;
    }
    public String getPublishedDate() {
        return publishedDate;
    }
    public void setPublishedDate(String publishedDate) {
        this.publishedDate = publishedDate;
    }
    public String getReviewLink() {
        return reviewLink;
    }
    public void setReviewLink(String reviewLink) {
        this.reviewLink = reviewLink;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }
}

所以请帮助我...如果您可以更正我的 ListProvider,那就太好了.class该错误显示在

@Override
    public int getCount() {
        return booksList.size();
    }

简洁的答案:Realm 结果是延迟加载的,所以我会说你不需要在另一个线程上执行查询。为 RemoteView(或 ListProvider(创建一个领域,然后像往常一样使用它进行查询。Realm 对象只会在被访问时加载数据。

相关内容

最新更新