0

我正在嘗試爲我的應用程序製作應用程序小部件並將最愛書列表顯示到應用程序小部件中。但是,它顯示錯誤:如何解決「領域訪問不正確的線程。領域對象只能在他們被創建的線程訪問」

「從不正確的線程訪問領域Realm對象只能在創建它們的線程上訪問 」。

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- ConfigActivity

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- ListProvider類

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- WidgetService類

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- WidgetProvider類

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 RemoteFetchService類

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- FavoriteBooks類擴展RealmObject

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其中的錯誤顯示on

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

異常stacktrace .... – EpicPandaForce

+0

檢查它,我加了 –

+0

我認爲有一個機會,Widget UI運行在一個單獨的*進程* – EpicPandaForce

回答

0

簡明答案:領域結果是懶加載的,所以我會說你不需要在另一個threa上執行查詢d。爲RemoteView(或ListProvider)創建一個領域,然後使用它作爲正常查詢。 Realm對象只會在訪問時加載數據。

+0

這不是在我的情況下工作我曾試過: –

相關問題