Многоуровневое извлечение ListView из базы данных - PullRequest
2 голосов
/ 20 января 2012

Я работаю над своим первым приложением для Android и сталкиваюсь с проблемой, для которой не могу найти решение. Я пытаюсь настроить свой пользовательский интерфейс с помощью серии списков, которые в конце соединятся со страницей, отображающей текст редактирования, который потребует ввода. IE Категории -> Источники -> Заголовки -> Edittexts наши, другими словами, они будут сначала отображаться список категорий (музыка, фильмы и т. Д.). Затем пользователь нажимает, скажем, «Музыка», после чего он перечисляет исполнителей в моей базе данных. После нажатия на исполнителя он отобразит их песни в моей базе данных. У меня есть atm, где он будет отображать мои установленные мной курсоры, но у меня возникли проблемы с настройкой моей программы, чтобы увидеть, что пользователь нажал, и отобразить курсор результатов / отображения, содержащий данные, которые я хочу показать.

public class dbadapter extends SQLiteOpenHelper {

     //The Android's default system path of your application database.
   public static final String DB_PATH = "/data/data/wanted.pro.madlibs/databases/";
   public static final String DB_NAME = "madlib";
   public static final int DB_VERSION = 1;
   private static final String TAG = "dbadapter";

   //database variables
   public static final String  KEY_ID = "_id";
   public static final String  KEY_CATEGORYDESC = "categorydesc";
   public static final String KEY_TITLE = "titlekey";
   public static final String KEY_TITLEDESC = "titledesc";
   public static final String KEY_TITLESTORY = "titlestory";
   public static final String KEY_SOURCEDESC = "sourcedesc";
   public static final String KEY_SOURCE = "sourcekey";
   public static final String KEY_CATEGORY = "categorykey";

   //table variables
   public static final String CATEGORY_TABLE = "category";
   public static final String SOURCE_TABLE = "source";
   public static final String TITLE_TABLE = "title";

   private dbadapter mydbhelper;
   private static SQLiteDatabase myDataBase; 


   @Override
   public void onOpen(SQLiteDatabase myDatabase)
   {
     super.onOpen(myDatabase);
     if (!myDatabase.isReadOnly())
     {
       // Enable foreign key constraints
       myDatabase.execSQL("PRAGMA foreign_keys=ON;");
     }
   }

   /**
    * Constructor
    * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
    * @param context
    */

       private final Context mCtx;
    public dbadapter(Context context) {

    super(context, DB_NAME, null, DB_VERSION);
       this.mCtx = context;
   }    

 /**
    * Creates a empty database on the system and rewrites it with your own database.
    * */
   public void createDataBase() throws IOException{

    boolean dbExist = checkDataBase();

    if(dbExist){
        //do nothing - database already exist
    }else{

        //By calling this method and empty database will be created into the default system path
              //of your application so we are gonna be able to overwrite that database with our database.
        this.getReadableDatabase();

        try {

            copyDataBase();

        } catch (IOException e) {

            throw new Error("Error copying database");

        }
    }


   }

   /**
    * Check if the database already exist to avoid re-copying the file each time you open the application.
    * @return true if it exists, false if it doesn't
    */
   private boolean checkDataBase(){

    SQLiteDatabase checkDB = null;

    try{
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    }catch(SQLiteException e){

        //database does't exist yet.

    }

    if(checkDB != null){

        checkDB.close();

    }

    return checkDB != null ? true : false;
   }

   /**
    * Copies your database from your local assets-folder to the just created empty database in the
    * system folder, from where it can be accessed and handled.
    * This is done by transferring bytestream.
    * */
   private void copyDataBase() throws IOException{

    //Open your local db as the input stream
    InputStream myInput = mCtx.getAssets().open(DB_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME;

    //Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    //transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer))>0){
        myOutput.write(buffer, 0, length);
    }

    //Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

   }

   public void openDataBase() throws SQLException{

    //Open the database
       String myPath = DB_PATH + DB_NAME;
    myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

   }

   @Override
    public synchronized void close() {

        if(myDataBase != null)
            myDataBase.close();

        super.close();

    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
        db.execSQL("DROP TABLE IF EXISTS category");
        onCreate(db);
    }

    public dbadapter open() throws SQLException {
        mydbhelper = new dbadapter (mCtx);
        myDataBase = mydbhelper.getWritableDatabase();
        return this;
    }



    // Add your public helper methods to access and get content from the database.
      // You could return cursors by doing "return myDataBase.query(....)" so it'd be easy
      // to you to create adapters for your views.

    // retrieves all the categories
      public static Cursor getAllCategories() 
        {
            return myDataBase.query(CATEGORY_TABLE, new String[] {
                    KEY_ID, KEY_CATEGORY,
                    KEY_CATEGORYDESC,
                    }, 
                    null, null, null, null, KEY_CATEGORYDESC);

        }
    // retrieves all the titles
          public Cursor getAllTitles() 
            {
                return myDataBase.query(TITLE_TABLE, new String[] {
                        KEY_ID, 
                        KEY_TITLE,
                        KEY_TITLEDESC,
                        KEY_TITLESTORY,
                        }, 
                        null, null, null, null, KEY_TITLEDESC);

            }
        // retrieves all the sources
          public  Cursor getAllSources() 
            {
                return myDataBase.query(SOURCE_TABLE, new String[] {
                        KEY_ID, 
                        KEY_SOURCE,
                        KEY_SOURCEDESC,
                        }, 
                        null, null, null, null, KEY_SOURCEDESC);

            }

Вот код моего адаптера

public class categories extends ListActivity {
    /** Called when the activity is first created. */
    private dbadapter mydbhelper;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.category_list);
        mydbhelper = new dbadapter(this);
        mydbhelper.open();
        fillData();
    }
    private void fillData() {
            Cursor c = mydbhelper.getAllCategories();
            startManagingCursor(c);

     // Create an array to specify the fields we want to display in the list (TITLE,DATE,NUMBER)
        String[] from = new String[] {dbadapter.KEY_CATEGORYDESC};

        // an array of the views that we want to bind those fields to (in this case text1,text2,text3)
        int[] to = new int[] {R.id.text1};

        // Now create a simple cursor adapter and set it to display
        SimpleCursorAdapter adapter = 
            new SimpleCursorAdapter(this, R.layout.cate_row, c, from, to);
        setListAdapter(adapter);
        }
@Override
protected void onListItemClick(ListView list, View v, int position, long id)
{
    super.onListItemClick(list, v, position, id);
    final Intent intent = new Intent(this, source.class);

    startActivityForResult(intent, position);
    }
}

это будет мой журнал sql, из которого я сделал таблицы базы данных

CREATE TABLE category(
_id INT,  
categorykey INT,
  categorydesc TEXT,
   PRIMARY KEY(_id)
);
CREATE TABLE source(
_id INT,  
sourcekey INT,
  sourcedesc TEXT,
   PRIMARY KEY(_id)
);
CREATE TABLE title(
_id INT,  
titlekey INT,
  titledesc TEXT,
titlestory TEXT,
   PRIMARY KEY(_id)
);
CREATE TABLE userword(
_id INT,  
titlekey INT,
  userword TEXT,
   PRIMARY KEY(_id), FOREIGN KEY(titlekey) REFERENCES title(titlekey)
);
CREATE TABLE category_title(
titlekey INT,
  categorykey INT,
  FOREIGN KEY(titlekey) REFERENCES title(titlekey), FOREIGN KEY (categorykey) REFERENCES category(categorykey)
);
CREATE TABLE source_title(
titlekey INT,
  sourcekey INT,
  FOREIGN KEY(titlekey) REFERENCES title(titlekey), FOREIGN KEY (sourcekey) REFERENCES source(sourcekey)
);
CREATE TABLE source_category(
sourcekey INT,
  categorykey INT,
  FOREIGN KEY(categorykey) REFERENCES category(categorykey), FOREIGN KEY (sourcekey) REFERENCES source(sourcekey)
);

Единственный известный мне курсор, который я имею право, - это Категория, поскольку это единственные данные в таблице базы данных, которые не будут отфильтрованы по ранее выбранным.

Ответы [ 2 ]

1 голос
/ 20 января 2012

Если я правильно понял ваш сценарий, вы задаетесь вопросом, как определить, какой объект (в частности, какая запись) был выбран. Это можно сделать довольно прямо, подсказал Билл Гэри. Есть два варианта:

  1. Используйте «положение» в качестве индикатора, куда двигаться с вашим текущий курс. на основе вашего текущего курсора и позиции, которую вы затем запросите один слой глубже.
  2. Используйте «Прокси-шаблон», чтобы провести четкое различие между логика и база данных. Я делаю это так. Вы создаете новый класс который представляет запись базы данных, например, категории. Вместо того, чтобы заполнять ваш адаптер чистыми данными базы данных, вставьте те объекты (так называемый прокси). Эти прокси имеют ссылку на соответствующая им запись в базе данных (через курсор). При нажатии предмет, вы можете просто попросить адаптер для предмета в этом месте. тогда вы можете задать этот пункт в вашей записи данных. Затем вы запросить вашу базу данных в следующем слое (Artist ...) для этого набора данных.

Для правильного запроса вы должны использовать оператор SELECT ... WHERE, который вы можете легко реализовать с помощью метода query (). Но, как вы используете этот метод, я думаю, вы знаете, как это сделать.

1 голос
/ 20 января 2012

Я использую нечто подобное, я использую отдельные таблицы для хранения моих списков. Шахта не заселена так, как вы будете использовать. У меня есть одно представление списка, которое заполнено списком таблиц, и когда вы нажимаете на элемент в списке, оно открывает другое представление списка, заполненное записями в выбранной таблице. Это то, что вы ищете?

EDIT

Глядя снова,

CREATE TABLE category(
_id INT,  
categorykey INT,
categorydesc TEXT,
PRIMARY KEY(_id)
);
CREATE TABLE source(
_id INT,  
sourcekey INT,
sourcedesc TEXT,
PRIMARY KEY(_id)
);

и т. Д. Создает отдельную таблицу для каждого, поэтому вам нужно изменить таблицу, чтобы получить другие списки. public static final String CATEGORY_TABLE = "category"; просто запрашивает таблицу Category для запроса источника таблицы, это должно быть public static final String CATEGORY_TABLE = "source";

Что я делаю, так это использую переменную, установленную в списке

String click = l.getItemAtPosition(position).toString();
table = click;

в моем onListItemClick() с table равным public static String table;, тогда для вашего запроса используйте table вместо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...