我仍然是面向对象编程的新手,我遇到了类继承问题以及从一个实例化类到另一个类的变量范围。
我正在尝试构建一个可以读取多个XML Feed的Android应用程序,并将它们保存到手机的SQLite数据库中。每个Feed都有一个不同的名称(“news”,“audio_mixes”等),我想使用这些名称将每个Feed的数据保存到单独的数据库表中 - 每个表都以Feed标题命名。
在图表术语中,这就是我的类的样子: alt text http://baroquedub.co.uk/private/images/Main-Title_Browser.jpg
主要活动显示两个按钮,每个按钮都会启动一个活动 - 这两个按钮都是TitlesBrowser类的实例。额外内容用于传递 the_url 和 the_feed_type 变量的不同值。
@Override
public void onCreate(final Bundle icicle) {
super.onCreate(icicle);
this.setContentView(R.layout.main);
this.getNewsButton = (Button) findViewById(R.id.get_news_button);
this.getNewsButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
Intent doGetNews = new Intent(Main.this, TitlesBrowser.class);
doGetNews.putExtra("the_url", Main.this.getString(R.string.titles_url));
doGetNews.putExtra("the_feed_type", Main.this.getString(R.string.news_type_var));
startActivity(doGetNews);
}
});
this.getMixtapesButton = (Button) findViewById(R.id.get_mixtapes_button);
this.getMixtapesButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
Intent doGetMixtapes = new Intent(Main.this, TitlesBrowser.class);
doGetMixtapes.putExtra("the_url", Main.this.getString(R.string.titles_url));
doGetMixtapes.putExtra("the_feed_type", Main.this.getString(R.string.mixtapes_type_var));
startActivity(doGetMixtapes);
}
});
}
TitlesBrowser类,在其onCreate方法中,获取Extras并将它们保存到私有局部变量。
Intent i = getIntent();
private String theUrl = (String) i.getStringExtra("the_url");
private String theFeedType = (String) i.getStringExtra("the_feed_type");</pre>
这门课做了两件事,
1 /它创建DatabaseHelper类的实例,并使用该类中的公共set方法传递本地帮助 theFeedType 变量的值。完成后,它会在数据库中查询任何现有数据( theFeedType 是每个表的名称)
db=new DatabaseHelper(this);
db.setTableName(theFeedType);
dbCursor=db.getReadableDatabase().rawQuery("SELECT _ID, id, title FROM "+theFeedType+" ORDER BY id", null);
2 /然后通过实例化另一个类HTTPRequestHelper从源URL加载新数据:
HTTPRequestHelper helper = new HTTPRequestHelper(responseHandler);
helper.performPost(theUrl, theFeedType);
HTTP请求正常工作,并且根据单击两个按钮中的哪一个,两个不同活动中的每一个都显示相应的XML(即检索正确的数据) - 因此我知道theUrl和theFeedType变量是TitlesBrowser类的每个实例的本地变量。 一个人打来电话:
http://baroquedub.co.uk/get-feed.php?feed=news
和另一个:
http://baroquedub.co.uk/get-feed.php?feed=audio_mixes
问题在于 DatabaseHelper类:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME="baroquedub.db";
private String table_name;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE "+ table_name + "(_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"id INTEGER, " +
"title TEXT, " +
"details TEXT, " +
"picture TEXT, " +
"viewed BOOLEAN DEFAULT '0' NOT NULL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
android.util.Log.w("Baroquedub", "Upgrading database, which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS mixtapes");
onCreate(db);
}
public void setTableName(String theName){
this.table_name = theName;
}
}
我希望每次实例化时都会创建一个新表(无论是“news”还是“audio_mixes”是从其父级TitlesBrowser类传递的。
但它只运行一次 - 如果我启动应用程序并单击“新闻”,则会创建一个名为news的表,每次返回该活动时,它都会成功从同一个数据库中检索数据。
但是,如果我通过单击另一个按钮(即访问另一个源)启动另一个活动,我会收到一个SQL错误,告诉我该名称的数据库不存在。换句话说,onCreate db.execSQL(“CREATE TABLE ...方法似乎不再被调用。
虽然有两个TitlesBrowser实例,但好像没有创建DatabaseHelper类的多个副本。
- 以下是该问题的演示:
http://screencast.com/t/NDFkZDFmMz
解释这一点非常棘手(特别是对于新手!!!)我希望它有一定道理。我非常感谢任何帮助,建议或指导。
答案 0 :(得分:1)
当你实例化一个SQLiteOpenHelper
类时,你实际上在Activity的上下文中访问一个单例。帮助程序决定何时调用OnCreate
/ onUpgrade
方法 - 具体来说,如果数据库不存在或过时。
无论哪种方式,每次创建类的新实例时都不会调用onCreate
方法 - 这实际上没有意义。您应该将两个CREATE TABLE
命令放在onCreate
方法中。
(PS我认为你得到的错误是缺少表而不是整个数据库)。
答案 1 :(得分:0)
非常感谢adamk在他提供的答案中提供解决此问题所需的指导。
他建议我在DatabaseHelper的onCreate方法中添加两个CREATE TABLE命令(对于我的每个提要都打开)。但是,我需要更多地抽象一些东西,以便我仍然可以使用TitlesBrowser活动的多个实例化,这样我就不必每次有新的Feed都重写辅助类。
对于那些感兴趣的人,这是我提出的解决方案。
首先,我删除了 DatabaseHelper 的onCreate方法中的CREATE TABLE命令。我还删除了私有table_name变量(及其相关的set方法),并将其替换为名为makeTable()的公共方法:
public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME="baroquedub.db"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, 1); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { android.util.Log.w("Baroquedub", "Upgrading database, which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS mixtapes"); onCreate(db); } public void makeTable(String theTableName){ SQLiteDatabase thisDB = DatabaseHelper.this.getWritableDatabase(); thisDB.execSQL("CREATE TABLE IF NOT EXISTS "+ theTableName + "(_id INTEGER PRIMARY KEY AUTOINCREMENT, " + "id INTEGER, " + "title TEXT, " + "details TEXT, " + "picture TEXT, " + "viewed BOOLEAN DEFAULT '0' NOT NULL);"); } }
在 TitlesBrowser 中,而不是实例化DatabaseHelper,设置表名然后读入数据:
db=new DatabaseHelper(this); db.setTableName(theFeedType); dbCursor=db.getReadableDatabase().rawQuery("SELECT _ID, id, title FROM "+theFeedType+" ORDER BY id", null);
相反,我重写了所有这些,以便更优雅地处理从每个表创建和加载数据库数据:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent i = getIntent(); theUrl = (String) i.getStringExtra("the_url"); theFeedType = (String) i.getStringExtra("the_feed_type"); // show saved in DB db=new DatabaseHelper(this); databaseLoad(); } private void databaseLoad(){ try { // table exists dbCursor=db.getReadableDatabase() .rawQuery("SELECT _ID, id, title FROM "+theFeedType+" ORDER BY id", null); displayContent(); } catch (Exception e) { // table doesn't exist db.makeTable(theFeedType); databaseLoad(); // try again } }