我正在尝试为我的应用制作应用小部件,并将收藏的商品列表显示到应用小部件中。但是,它显示错误:
" 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,那将是很好的,
@Override
public int getCount() {
return booksList.size();
}
答案 0 :(得分:0)
简明回答:Realm结果是延迟加载的,所以我说你不需要在另一个线程上执行查询。为RemoteView(或ListProvider)创建一个领域,然后使用它来正常查询。 Realm对象只会在访问时加载数据。