Android活动类中的面向对象范围和继承

时间:2010-07-28 14:34:27

标签: android database class inheritance oop

我仍然是面向对象编程的新手,我遇到了类继承问题以及从一个实例化类到另一个类的变量范围。

我正在尝试构建一个可以读取多个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

解释这一点非常棘手(特别是对于新手!!!)我希望它有一定道理。我非常感谢任何帮助,建议或指导。

2 个答案:

答案 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);

相反,我重写了所有这些,以便更优雅地处理从每个表创建和加载数据库数据:

  1. 数据库助手像以前一样创建
  2. 然后新的databaseLoad()方法尝试从必需的表中读取
  3. 如果不能,则调用DatabaseHelper的public makeTable()方法,
  4. 在最终再次尝试加载数据之前:
  5.    @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
            }
        }