0

J'essaie de créer un widget app pour mon application et d'afficher la liste des favoris dans le widget app. Cependant, il indique l'erreur: «accès à l'espace de fil incorrect des objets de royaume ne peuvent être accessibles sur le fil, ils ont été créés. »Comment résoudre "Accès au domaine depuis un thread incorrect Les objets du domaine ne sont accessibles que sur le thread qu'ils ont été créés"

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 

Si vous en savez s'il vous plaît me donner un exemple clair sur les données d'accès à d'autres activités ou comment appeler thread particulier où la base de données de domaine créé.

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

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 classe

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 classe étend 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; 
    } 
} 

Alors S'il vous plaît aidez-moi ... Ce serait génial si vous pouviez corriger mes ListProvider.class où que les émissions d'erreur sur

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

Exception stacktrace .... – EpicPandaForce

+0

vérifier, j'ai ajouté –

+0

Je pense qu'il ya une chance que Widget UI s'exécute dans un processus * distinct * – EpicPandaForce

Répondre

0

Réponse concise: les résultats de domaine sont faiblement chargés, donc je dirais que vous n'avez pas besoin d'effectuer la requête sur un autre thème. ré. Créez un domaine pour RemoteView (ou ListProvider), puis utilisez-le pour interroger normalement. L'objet Realm ne chargera les données que lorsqu'il sera accédé.

+0

Ça ne marche pas dans mon cas je l'avais essayé: –