带有 AsyncTask 和 SQLite 游标的 NullPointerException
好吧,我很困惑。我发布的一个应用程序出现错误 ANR keyDispatchingTimedOut
,因此在修复该问题时,我以为我可以使用 AsyncTask 访问我的数据库,但我不断收到 NPE。另外,它不会填充列表视图,直到我单击“添加”按钮然后单击“后退”,因此它会在 onResume 中填充列表视图,但不会在 onCreate 中填充列表视图。这是活动代码。
public class View extends ListActivity implements OnClickListener {
String loc;
SharedPreferences data;
public static String filename = "Location";
private DBase db;
public static String vLoc = null, vId = null, vSong = null, vNumber = null;
Button bNLAdd, bNLBack;
TextView tvNLList;
Cursor c;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.notepad_list);
getLoc();
initialize();
fillData();
}
@Override
public void onClick(android.view.View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.bNLAdd:
startActivity(new Intent("com.ADD")); // edited to remove package name
break;
case R.id.bNLBack:
finish();
break;
}
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
fillData();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (c != null && !c.isClosed()) {
c.close();
}
db.close();
}
@Override
protected void onListItemClick(ListView l, android.view.View v,
int position, long id) { // TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
vLoc = loc;
vId = (String) ((Cursor) l.getItemAtPosition(position)).getString(0);
vSong = (String) ((Cursor) l.getItemAtPosition(position)).getString(1);
vNumber = (String) ((Cursor) l.getItemAtPosition(position))
.getString(2);
startActivity(new Intent("com.EDIT")); // edited to remove package name
}
private void fillData() {
// Get all of the notes from the database and create the item list
new getCursor().execute(loc);
startManagingCursor(c);
String[] from = new String[] { DBase.KEY_2SONG, DBase.KEY_2NUMBER };
int[] to = new int[] { R.id.text1, R.id.text2 };
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);
setListAdapter(notes);
}
private void getLoc() {
// TODO Auto-generated method stub
data = getSharedPreferences(filename, 0);
loc = data.getString("loc", null);
}
private void initialize() {
// TODO Auto-generated method stub
tvNLList = (TextView) findViewById(R.id.tvNLList);
tvNLList.setText("Song List for Location " + loc);
bNLAdd = (Button) findViewById(R.id.bNLAdd);
bNLBack = (Button) findViewById(R.id.bNLBack);
bNLAdd.setOnClickListener(this);
bNLBack.setOnClickListener(this);
}
public class getCursor extends AsyncTask<String, Integer, Cursor> {
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected Cursor doInBackground(String... params) {
// TODO Auto-generated method stub
db = new DBase(View.this);
db.open();
try {
c = db.fetchData(loc);
} catch (NullPointerException e) {
// TODO: handle exception
e.printStackTrace();
} finally {
if (c != null) {
return c;
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Cursor c) {
// TODO Auto-generated method stub
super.onPostExecute(c);
}
}
}
这是 logcat。
02-12 16:10:03.834: WARN/System.err(549): java.lang.NullPointerException
02-12 16:10:04.074: WARN/System.err(549): at com.DBase.fetchData(DBase.java:89)
02-12 16:10:04.074: WARN/System.err(549): at com.View$getCursor.doInBackground(View.java:134)
02-12 16:10:04.074: WARN/System.err(549): at com.View$getCursor.doInBackground(View.java:1)
02-12 16:10:04.074: WARN/System.err(549): at android.os.AsyncTask$2.call(AsyncTask.java:185)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
02-12 16:10:04.074: WARN/System.err(549): at java.lang.Thread.run(Thread.java:1096)
这是logcat中提到的DBase代码。
public Cursor fetchData(String loc) {
// TODO Auto-generated method stub
return ourDatabase.query(loc, new String[] { KEY_ROWID, KEY_2SONG, KEY_2NUMBER },
null, null, null, null, null);
}
我知道我一定错过了一些东西。我尝试将 startManagingCursor(c);
放在 onPostExecute 中,在 onCreate 中初始化数据库并使用 asyncTask 来提取数据等。
任何帮助将不胜感激。
这里编辑的是 DBase 类的其余部分。在我尝试 AsyncTask 之前它一直工作得很好。
public class DBase {
public static final String KEY_ROWID = "_id";
public static final String KEY_2TBL = "loc";
public static final String KEY_2SONG = "Song";
public static final String KEY_2NUMBER = "Number";
private static final String DATABASE_NAME = "Tracker";
static final String DATABASE_TABLE = "TempTable";
private static final int DATABASE_VERSION = 1;
private DbHelper ourHelper;
private final Context ourContext;
private SQLiteDatabase ourDatabase;
private static class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_2TBL
+ " TEXT NOT NULL, " + KEY_2NUMBER + " TEXT NOT NULL, "
+ KEY_2SONG + " TEXT NOT NULL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
onCreate(db);
}
}
public DBase(Context c) {
ourContext = c;
}
public DBase open() throws SQLException {
ourHelper = new DbHelper(ourContext);
ourDatabase = ourHelper.getWritableDatabase();
return this;
}
public void close() {
ourHelper.close();
}
public void deleteEntry(long dId, String loc) {
ourDatabase.delete(loc, KEY_ROWID + "=" + dId, null);
}
public long addTable(String loc) {
// TODO Auto-generated method stub
ourDatabase.execSQL("CREATE TABLE IF NOT EXISTS " + loc + " ("
+ KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_2TBL
+ " TEXT NOT NULL, " + KEY_2SONG + " TEXT NOT NULL, "
+ KEY_2NUMBER + " TEXT NOT NULL);");
ContentValues cv = new ContentValues();
cv.put(KEY_2TBL, loc);
return ourDatabase.insert(loc, null, cv);
}
public Cursor fetchData(String loc) {
// TODO Auto-generated method stub
return ourDatabase.query(loc, new String[] { KEY_ROWID, KEY_2SONG, KEY_2NUMBER },
null, null, null, null, null);
}
public long createEntry(String loc, String sSong, String sNumber) {
// TODO Auto-generated method stub
ContentValues cv = new ContentValues();
cv.put(KEY_2TBL, loc);
cv.put(KEY_2SONG, sSong);
cv.put(KEY_2NUMBER, sNumber);
return ourDatabase.insert(loc, null, cv);
}
public ArrayList<String> listTables() {
ArrayList<String> tableList = new ArrayList<String>();
String SQL_GET_ALL_TABLES = "SELECT name FROM "
+ "sqlite_master WHERE type='table' ORDER BY name";
Cursor c = ourDatabase.rawQuery(SQL_GET_ALL_TABLES, null);
c.moveToFirst();
if (!c.isAfterLast()) {
do {
tableList.add(c.getString(0));
} while (c.moveToNext());
}
c.close();
return tableList;
}
public void editSong(long eId, String loc, String eSong, String eNumber) {
// TODO Auto-generated method stub
ContentValues cvUpdate = new ContentValues();
cvUpdate.put(KEY_2TBL, loc);
cvUpdate.put(KEY_2SONG, eSong);
cvUpdate.put(KEY_2NUMBER, eNumber);
ourDatabase.update(loc, cvUpdate, KEY_ROWID + "=" + eId, null);
}
public void deleteTable(String loc) {
// TODO Auto-generated method stub
ourDatabase.execSQL("DROP TABLE " + loc );
}
}
Ok, I'm stumped. I have an app that I've published that had the error ANR keyDispatchingTimedOut
so while fixing that, I thought I'd access my DB with AsyncTask but I keep getting an NPE. Also, it doesn't populate the listview until I click the add button then click back, so it's populating the listview in onResume but not onCreate. Here is the activity code.
public class View extends ListActivity implements OnClickListener {
String loc;
SharedPreferences data;
public static String filename = "Location";
private DBase db;
public static String vLoc = null, vId = null, vSong = null, vNumber = null;
Button bNLAdd, bNLBack;
TextView tvNLList;
Cursor c;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.notepad_list);
getLoc();
initialize();
fillData();
}
@Override
public void onClick(android.view.View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.bNLAdd:
startActivity(new Intent("com.ADD")); // edited to remove package name
break;
case R.id.bNLBack:
finish();
break;
}
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
fillData();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (c != null && !c.isClosed()) {
c.close();
}
db.close();
}
@Override
protected void onListItemClick(ListView l, android.view.View v,
int position, long id) { // TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
vLoc = loc;
vId = (String) ((Cursor) l.getItemAtPosition(position)).getString(0);
vSong = (String) ((Cursor) l.getItemAtPosition(position)).getString(1);
vNumber = (String) ((Cursor) l.getItemAtPosition(position))
.getString(2);
startActivity(new Intent("com.EDIT")); // edited to remove package name
}
private void fillData() {
// Get all of the notes from the database and create the item list
new getCursor().execute(loc);
startManagingCursor(c);
String[] from = new String[] { DBase.KEY_2SONG, DBase.KEY_2NUMBER };
int[] to = new int[] { R.id.text1, R.id.text2 };
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);
setListAdapter(notes);
}
private void getLoc() {
// TODO Auto-generated method stub
data = getSharedPreferences(filename, 0);
loc = data.getString("loc", null);
}
private void initialize() {
// TODO Auto-generated method stub
tvNLList = (TextView) findViewById(R.id.tvNLList);
tvNLList.setText("Song List for Location " + loc);
bNLAdd = (Button) findViewById(R.id.bNLAdd);
bNLBack = (Button) findViewById(R.id.bNLBack);
bNLAdd.setOnClickListener(this);
bNLBack.setOnClickListener(this);
}
public class getCursor extends AsyncTask<String, Integer, Cursor> {
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected Cursor doInBackground(String... params) {
// TODO Auto-generated method stub
db = new DBase(View.this);
db.open();
try {
c = db.fetchData(loc);
} catch (NullPointerException e) {
// TODO: handle exception
e.printStackTrace();
} finally {
if (c != null) {
return c;
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Cursor c) {
// TODO Auto-generated method stub
super.onPostExecute(c);
}
}
}
And here is the logcat.
02-12 16:10:03.834: WARN/System.err(549): java.lang.NullPointerException
02-12 16:10:04.074: WARN/System.err(549): at com.DBase.fetchData(DBase.java:89)
02-12 16:10:04.074: WARN/System.err(549): at com.View$getCursor.doInBackground(View.java:134)
02-12 16:10:04.074: WARN/System.err(549): at com.View$getCursor.doInBackground(View.java:1)
02-12 16:10:04.074: WARN/System.err(549): at android.os.AsyncTask$2.call(AsyncTask.java:185)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
02-12 16:10:04.074: WARN/System.err(549): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
02-12 16:10:04.074: WARN/System.err(549): at java.lang.Thread.run(Thread.java:1096)
And here is the DBase code mentioned in the logcat.
public Cursor fetchData(String loc) {
// TODO Auto-generated method stub
return ourDatabase.query(loc, new String[] { KEY_ROWID, KEY_2SONG, KEY_2NUMBER },
null, null, null, null, null);
}
I know i must be missing something. I tried putting the startManagingCursor(c);
in the onPostExecute, initializing the dbase in onCreate and using the asyncTask to just pull the data, etc.
Any help will be appreciated.
EDIT here is the rest of the DBase class. It was working perfectly until I tried AsyncTask.
public class DBase {
public static final String KEY_ROWID = "_id";
public static final String KEY_2TBL = "loc";
public static final String KEY_2SONG = "Song";
public static final String KEY_2NUMBER = "Number";
private static final String DATABASE_NAME = "Tracker";
static final String DATABASE_TABLE = "TempTable";
private static final int DATABASE_VERSION = 1;
private DbHelper ourHelper;
private final Context ourContext;
private SQLiteDatabase ourDatabase;
private static class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_2TBL
+ " TEXT NOT NULL, " + KEY_2NUMBER + " TEXT NOT NULL, "
+ KEY_2SONG + " TEXT NOT NULL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
onCreate(db);
}
}
public DBase(Context c) {
ourContext = c;
}
public DBase open() throws SQLException {
ourHelper = new DbHelper(ourContext);
ourDatabase = ourHelper.getWritableDatabase();
return this;
}
public void close() {
ourHelper.close();
}
public void deleteEntry(long dId, String loc) {
ourDatabase.delete(loc, KEY_ROWID + "=" + dId, null);
}
public long addTable(String loc) {
// TODO Auto-generated method stub
ourDatabase.execSQL("CREATE TABLE IF NOT EXISTS " + loc + " ("
+ KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_2TBL
+ " TEXT NOT NULL, " + KEY_2SONG + " TEXT NOT NULL, "
+ KEY_2NUMBER + " TEXT NOT NULL);");
ContentValues cv = new ContentValues();
cv.put(KEY_2TBL, loc);
return ourDatabase.insert(loc, null, cv);
}
public Cursor fetchData(String loc) {
// TODO Auto-generated method stub
return ourDatabase.query(loc, new String[] { KEY_ROWID, KEY_2SONG, KEY_2NUMBER },
null, null, null, null, null);
}
public long createEntry(String loc, String sSong, String sNumber) {
// TODO Auto-generated method stub
ContentValues cv = new ContentValues();
cv.put(KEY_2TBL, loc);
cv.put(KEY_2SONG, sSong);
cv.put(KEY_2NUMBER, sNumber);
return ourDatabase.insert(loc, null, cv);
}
public ArrayList<String> listTables() {
ArrayList<String> tableList = new ArrayList<String>();
String SQL_GET_ALL_TABLES = "SELECT name FROM "
+ "sqlite_master WHERE type='table' ORDER BY name";
Cursor c = ourDatabase.rawQuery(SQL_GET_ALL_TABLES, null);
c.moveToFirst();
if (!c.isAfterLast()) {
do {
tableList.add(c.getString(0));
} while (c.moveToNext());
}
c.close();
return tableList;
}
public void editSong(long eId, String loc, String eSong, String eNumber) {
// TODO Auto-generated method stub
ContentValues cvUpdate = new ContentValues();
cvUpdate.put(KEY_2TBL, loc);
cvUpdate.put(KEY_2SONG, eSong);
cvUpdate.put(KEY_2NUMBER, eNumber);
ourDatabase.update(loc, cvUpdate, KEY_ROWID + "=" + eId, null);
}
public void deleteTable(String loc) {
// TODO Auto-generated method stub
ourDatabase.execSQL("DROP TABLE " + loc );
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
抱歉,比尔,这有点像大杂烩。您正在启动一个应该填充实例变量
c
的 AsyncTask,然后几乎肯定在c
之前立即调用c
上的startManagingCursor()
code>AsyncTask 已运行第一行。我强烈怀疑这就是它在onResume
而不是onCreate
中工作的原因,因为onResume
实际上会有一个填充的c
。就个人而言,如果您确实希望所有内容都基于 AsyncTask,那么所有内容都基于 AsyncTask。在
onPostExecute()
之前不要使用startManagingCursor()
或setListAdapter()
。不知道您的
DBView
到 NPE 的内部发生了什么,尽管从发布的代码来看很可能是ourDatabase
此时为空。Sorry, Bill, that's kind of a hodge-podge. You're kicking off an AsyncTask that's supposed to populate an instance variable
c
, then immediately callingstartManagingCursor()
onc
almost certainly before theAsyncTask
has run the first line. I strongly suspect that's why it works inonResume
instead ofonCreate
sinceonResume
will actually have a populatedc
.Personally, if you really want to base everything off an AsyncTask, base everything off the AsyncTask. Don't
startManagingCursor()
orsetListAdapter()
untilonPostExecute()
.No idea what's going on internally in your
DBView
to NPE, though it's most likely from the posted code that it'sourDatabase
that's null at that point.