我正在使用listview和上下文菜单。当用户长时间按下上下文菜单中的项目时,列表中项目旁边会出现一个小标记,让用户知道该项目已被标记为收藏夹。这一切都运作良好,除了它导致力量在第一次完成时关闭。每隔一段时间工作得很好。 以下是相关代码:
@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):致命 EXCEPTION:后台线程 E / AndroidRuntime(5362): android.view.ViewRoot $ CalledFromWrongThreadException: 只创建了原始线程 视图层次结构可以触及其视图。 E / AndroidRuntime(5362):at android.view.ViewRoot.checkThread(ViewRoot.java:2932) E / AndroidRuntime(5362):at android.view.ViewRoot.requestLayout(ViewRoot.java:629) E / AndroidRuntime(5362):at android.view.View.requestLayout(View.java:8267) E / AndroidRuntime(5362):at android.view.View.requestLayout(View.java:8267) E / AndroidRuntime(5362):at android.view.View.requestLayout(View.java:8267) E / AndroidRuntime(5362):at android.view.View.requestLayout(View.java:8267) E / AndroidRuntime(5362):at android.widget.AbsListView.requestLayout(AbsListView.java:1102) E / AndroidRuntime(5362):at android.widget.AdapterView $ AdapterDataSetObserver.onChanged(AdapterView.java:790) E / AndroidRuntime(5362):at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:31) E / AndroidRuntime(5362):at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50) E / AndroidRuntime(5362):at android.widget.CursorAdapter.changeCursor(CursorAdapter.java:260) E / AndroidRuntime(5362):at com.zalzala.spellbookpf.SpellsAz $ bgRequery.onPostExecute(SpellsAz.java:228) E / AndroidRuntime(5362):at com.zalzala.spellbookpf.SpellsAz $ bgRequery.onPostExecute(SpellsAz.java:1) E / AndroidRuntime(5362):at 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线程是一个好习惯,所以我仍然会喜欢一些帮助来解决这个问题。
答案 0 :(得分:0)
您是否尝试过使用runOnUiThread方法?基本上它看起来像这样:
runOnUiThread(new Runnable() {
public void run() {
spellsAdapter.changeCursor(mSpellCursor);
}
});
这样你可以在一个单独的线程中进行任何长时间的计算,但是当需要更新UI时,可以在正确的线程中完成。
答案 1 :(得分:0)
您必须使用处理程序才能管理UI对象。
如果不使用带有可运行的处理程序,则不能(并且不能)使用或触摸spellsAdapter
到AsyncTask中。
起初我很难理解这类问题并处理它们。但是,当我把它想象成两条不同速度的道路时,并没有那么多。你需要一些桥梁和控制来管理汽车;)相互信息。这就是Handler存在的原因
答案 2 :(得分:0)
异步任务有时可能会溢出。你最好在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;
}
}
}