如何解决changeCursor导致CalledFromWrongThreadException异常…,但仅一次
|| 我正在使用列表视图和上下文菜单。当用户长按上下文菜单中的某个项目时,列表中该项目旁边会出现一个小标记,以使用户知道该项目已被标记为收藏。一切都很好,除了它会在第一次完成时导致强制闭合。每隔一段时间就可以了。 以下是相关代码: @Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case 0:
mDbHelper.updateFavorite(info.id,1);
new bgRequery().execute();
return true;
case 1:
mDbHelper.updateFavorite(info.id,0);
new bgRequery().execute();
return true;
default:
return super.onContextItemSelected(item);
}
}
private class bgRequery extends AsyncTask<Void,Integer,Void> {
@Override
protected Void doInBackground(Void... voids ) {
mSpellCursor = fetchCursor();
return null;
}
@Override
protected void onPostExecute(Void voids) {
spellsAdapter.changeCursor(mSpellCursor);
}
}
这是例外:
D / SpellBook(5362):获取游标
E / AndroidRuntime(5362):致命
例外:后台线程
E / AndroidRuntime(5362):
android.view.ViewRoot $ CalledFromWrongThreadException:
只有创建的原始线程
视图层次结构可以触摸其视图。
E / AndroidRuntime(5362):在
android.view.ViewRoot.checkThread(ViewRoot.java:2932)
E / AndroidRuntime(5362):在
android.view.ViewRoot.requestLayout(ViewRoot.java:629)
E / AndroidRuntime(5362):在
android.view.View.requestLayout(View.java:8267)
E / AndroidRuntime(5362):在
android.view.View.requestLayout(View.java:8267)
E / AndroidRuntime(5362):在
android.view.View.requestLayout(View.java:8267)
E / AndroidRuntime(5362):在
android.view.View.requestLayout(View.java:8267)
E / AndroidRuntime(5362):在
android.widget.AbsListView.requestLayout(AbsListView.java:1102)
E / AndroidRuntime(5362):在
android.widget.AdapterView $ AdapterDataSetObserver.onChanged(AdapterView.java:790)
E / AndroidRuntime(5362):在
android.database.DataSetObservable.notifyChanged(DataSetObservable.java:31)
E / AndroidRuntime(5362):在
android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
E / AndroidRuntime(5362):在
android.widget.CursorAdapter.changeCursor(CursorAdapter.java:260)
E / AndroidRuntime(5362):在
com.zalzala.spellbookpf.SpellsAz $ bgRequery.onPostExecute(SpellsAz.java:228)
E / AndroidRuntime(5362):在
com.zalzala.spellbookpf.SpellsAz $ bgRequery.onPostExecute(SpellsAz.java:1)
E / AndroidRuntime(5362):在
android.os.AsyncTask.finish(AsyncTask.java:417)
因此,当spellsAdapter.changeCursor(mSpellCursor);发生错误时,在onPostExecute中被调用。由于该函数在ui线程中运行,因此我很难理解为什么会出现后台Tread错误。使这种情况难以理解和调试的原因是,它实际上仅在我第一次执行此操作时发生。每隔一段时间,即使应用程序重新启动或手机重新启动,它也能正常工作。重现此错误的唯一方法是卸载应用程序并重新安装它。
万一有人需要它,我将包括我的适配器的代码:
public class SpellListAdapter extends CursorAdapter {
private LayoutInflater mLayoutInflater;
private Context mContext;
public SpellListAdapter(Context context,Cursor c) {
super(context,c);
mContext = context;
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public View newView(Context context,Cursor cursor,ViewGroup parent) {
View v = mLayoutInflater.inflate(R.layout.list_item_fave,parent,false);
return v;
}
@Override
public void bindView(View v,Context context,Cursor c) {
String spell = c.getString(c.getColumnIndexOrThrow(SpellDbAdapter.KEY_SPELL));
int fave = c.getInt(c.getColumnIndexOrThrow(SpellDbAdapter.KEY_FAVORITE));
/**
* Next set the title of the entry.
*/
TextView Spell = (TextView) v.findViewById(R.id.text);
if (Spell != null) {
Spell.setText(spell);
}
//Set Fave Icon
TextView Fave = (TextView) v.findViewById(R.id.fave_icon);
Fave.setVisibility(View.INVISIBLE);
if (fave == 1){
Fave.setVisibility(View.VISIBLE);
}
}
public void update() {
notifyDataSetChanged();
}
}
谢谢你的帮助。
编辑:
我可以通过不在单独的线程中调用游标来解决此问题,但是我认为这是对它使用另一个线程而不是使用ui线程的一种好习惯,因此我仍然很乐于帮助您解决此问题。
解决方法
异步任务有时可能会溢出。您最好在CursorAdapter的onContentChanged中使用自己的线程。这是我的代码供您参考:
private class NearbyLocationListAdapter extends CursorAdapter
{
private static final String TAG = \"NearbyLocationListAdapter\";
private NearbyLocationActivity mActivity = null;
private Thread mContentChanageHanderThread = null;
public NearbyLocationListAdapter(NearbyLocationActivity activity,Cursor c) {
super(activity,c,false);
this.mActivity = activity;
}
// called when adding location info into location db
@Override
protected void onContentChanged() {
// AsyncTask will bring RejectedExecutionException,change to use Thread
// interrupt the original thread since data is updated again
clearContentChanageHanderThread();
mContentChanageHanderThread = new Thread(new Runnable() {
// set as synchronized in case called by multiple thread
@Override
public synchronized void run() {
if (Thread.currentThread().isInterrupted()) {
// Log.d(TAG,\"Thread interrupted. Aborting.\");
return;
}
final Cursor cursor = getLocationCursor();
if (Thread.currentThread().isInterrupted()) {
// Log.d(TAG,\"Thread interrupted after getting cursor. Aborting.\");
if (Util.isValid(cursor)) {
cursor.close();
}
return;
}
NearbyLocationActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
if (Util.isValid(cursor)) {
// will close the original cursor and switch to new one
// notifyDataSetChanged will be called inside
// Log.d(TAG,\"onContentChanged: will changeCursor\");
changeCursor(cursor);
}
else {
Log.e(TAG,\"onContentChanged: cursor is null or closed\");
}
}
});
}
});
mContentChanageHanderThread.start();
}
.....................................
public void clearContentChanageHanderThread() {
//Log.v(TAG,\"clearContentChanageHanderThread\");
if (mContentChanageHanderThread != null && mContentChanageHanderThread.isAlive()) {
mContentChanageHanderThread.interrupt();
mContentChanageHanderThread = null;
}
}
}
, 您是否尝试过使用runOnUiThread方法?基本上看起来像这样:
runOnUiThread(new Runnable() {
public void run() {
spellsAdapter.changeCursor(mSpellCursor);
}
});
这样,您可以在单独的线程中执行任何长时间的计算,但是当需要更新UI时,这是在正确的线程中完成的。
, 您必须使用Handler才能管理UI对象。
如果不使用带有可运行程序的处理程序,则不能(也不能)使用或触摸ѭ4进入AsyncTask。
起初我理解这种问题并加以处理真是太恐怖了。但是当我想到两条速度不同的道路时,它就不那么多了。您需要一些桥梁和控制权来管理汽车;)彼此之间的信息。这就是处理程序存在的原因
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。