Объектно-ориентированная область действия и наследование в классах активности Android - PullRequest
2 голосов
/ 28 июля 2010

Я все еще очень плохо знаком с объектно-ориентированным программированием, и у меня возникают проблемы с наследованием классов и областью действия переменных от одного экземпляра класса к другому.

Я пытаюсь создать приложение для Android, которое можетчитать несколько каналов XML и сохранять их в базе данных SQLite телефона.Каждый канал имеет свое имя («news», «audio_mixes» и т. Д.), И я хочу использовать эти имена для сохранения данных каждого канала в отдельных таблицах базы данных, каждая из которых названа в честь заголовка канала.

В диаграммеВ терминах вот так выглядят мои классы: альтернативный текст 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 получаетЭкстра и сохраняет их в частные локальные переменные.

<code>Intent i = getIntent();
private String theUrl = (String) i.getStringExtra("the_url");
private String theFeedType = (String) i.getStringExtra("the_feed_type");

Этот класс выполняет две функции:

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 / затем загружает новые данные из URL-адреса канала путем создания другого экземпляра.класс HTTPRequestHelper:

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;
  }
}

Iожидал, что он будет создавать новую таблицу каждый раз, когда она создается (независимо от того, были ли переданы «news» или «audio_mixes» из родительского класса TitlesBrowser.

Но это работает только один раз - если я запустил приложение и нажал на«news» создается таблица с названием news, и каждый раз, когда я возвращаюсь к этому действию, она успешно извлекает данные из той же базы данных.

Но если я затем запускаю другое действие, нажимая на другую кнопку (то есть доступ кдругой канал) Я получаю сообщение об ошибке SQL, сообщающее, что база данных с таким именем не существует. Другими словами, метод onCreate db.execSQL («CREATE TABLE ...» не вызывается снова.

Как будто несколько копий класса DatabaseHelper не создаются, хотя существует два экземпляра TitlesBrowser.

- Вот демонстрация проблемы:

http://screencast.com/t/NDFkZDFmMz

Это было очень сложно объяснить (особенно для новичка !!!), и я надеюсь, что в этом есть какой-то смысл.Я был бы очень благодарен за любую помощь, совет или руководство.

Ответы [ 2 ]

1 голос
/ 28 июля 2010

Когда вы создаете класс SQLiteOpenHelper, вы фактически получаете доступ к одиночному элементу в контексте действия. Помощник решает, когда вызывать методы OnCreate / onUpgrade, в частности, если БД не существует или устарела.

В любом случае, метод onCreate не вызывается каждый раз, когда вы создаете новый экземпляр класса - это действительно не имеет смысла. Вы должны поместить две команды CREATE TABLE в метод onCreate.

(PS Я предполагаю, что ошибка, которую вы получаете, заключается в том, что таблица отсутствует, а не вся база данных).

0 голосов
/ 30 июля 2010

Большое спасибо adamk за предоставленные рекомендации, необходимые для решения этой проблемы, в ответе, который он дал.

Он предложил добавить две команды CREATE TABLE в метод onCreate в DatabaseHelper (для каждого из моих каналов). Однако мне нужно было абстрагироваться немного больше, чтобы я мог использовать несколько экземпляров действия TitlesBrowser и чтобы мне не приходилось переписывать класс помощника каждый раз, когда на канал поступал новый фид.

Для тех, кто заинтересован, вот решение, которое я придумал.

Прежде всего я удалил команды CREATE TABLE в методе onCreate DatabaseHelper . Я также удалил личную переменную 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. База данных Helper создается как и раньше,
  2. затем новый метод databaseLoad () пытается прочитать из требуемой таблицы
  3. и, если это невозможно, он вызывает открытый метод makeTable () компонента DatabaseHelper,
  4. прежде чем наконец попытаться загрузить данные снова:
   @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
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...