Как отобразить базу данных SQLite в виде списка класса фрагмента? - PullRequest
0 голосов
/ 11 июня 2018

Я новичок в Android Studio.У меня есть база данных SQLite с тремя столбцами, и я хотел бы отобразить все данные в виде списка.База данных находится в папке активов.Я пытался сделать с SimpleCursorAdapter в классе фрагмента, но безуспешно.При запуске приложения на моем устройстве происходит сбой приложения.Может кто-нибудь сказать мне, почему?

Это мой фрагмент класса:

public class rightFragment extends Fragment {

View view;
Cursor c;
SimpleCursorAdapter adapter;
ListView listView;
Button buttondisplay;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

   view = inflater.inflate (R.layout.fragment_right, container, false);

     DatabaseHelper myDbHelper = new DatabaseHelper (getActivity ());
    try {
        myDbHelper.createDataBase ();
    } catch (IOException ioe) {

    }
    try {
        myDbHelper.openDataBase ();
    } catch (SQLException sqle) {
        throw sqle;
    }

    c = myDbHelper.query ("fradeu", null, null, null, null, null, null);


    Cursor c = myDbHelper.readData ();
    String[] from = new String []{DatabaseHelper.COL1,DatabaseHelper.COL2};
    int[] to = new int[] {R.id.fra, R.id.deu};

    adapter = new SimpleCursorAdapter (getActivity (), R.layout.list_view_adapter, c, from, to) {
    };

    buttondisplay.setOnClickListener (new View.OnClickListener () {
        @Override
        public void onClick(View v) {

            adapter.notifyDataSetChanged();
            listView.setAdapter(adapter);
        }
});
return view
}
}

DatabaseHelper:

public class DatabaseHelper extends SQLiteOpenHelper {

String DB_PATH = null;
private static String DB_NAME = "mydatabase3.db";
private SQLiteDatabase database;
private final Context myContext;
public static final String TABLE_NAME = "fradeu";
public static final String COL1 = "fra";
public static final String COL2 = "deu";

public DatabaseHelper(Context context) {
    super (context, DB_NAME, null, 10);
    this.myContext = context;
    this.DB_PATH = "/data/data/" + context.getPackageName () + "/" + "databases/";
    Log.e ("Path 1", DB_PATH);
}


public void createDataBase() throws IOException {
    boolean dbExist = checkDataBase ();
    if (dbExist) {
    } else {
        this.getReadableDatabase ();
        try {
            copyDataBase ();
        } catch (IOException e) {
            throw new Error ("Error copying database");
        }
    }
}

private boolean checkDataBase() {
    SQLiteDatabase checkDB = null;
    try {
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
    } catch (SQLiteException e) {
    }
    if (checkDB != null) {
        checkDB.close ();
    }
    return checkDB != null ? true : false;
}

private void copyDataBase() throws IOException {
    InputStream myInput = myContext.getAssets ().open (DB_NAME);
    String outFileName = DB_PATH + DB_NAME;
    OutputStream myOutput = new FileOutputStream (outFileName);
    byte[] buffer = new byte[10];
    int length;
    while ((length = myInput.read (buffer)) > 0) {
        myOutput.write (buffer, 0, length);
    }
    myOutput.flush ();
    myOutput.close ();
    myInput.close ();
}

public void openDataBase() throws SQLException {
    String myPath = DB_PATH + DB_NAME;
    database = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
}

public Cursor readData(){
    String[] allColumns = new String[] {DatabaseHelper.COL1,DatabaseHelper.COL2};
    Cursor c =database.query (DatabaseHelper.TABLE_NAME,allColumns,null,null,null,null,null);
    if(c != null) {
        c.moveToFirst ();

    }
    return c;
}

@Override
public synchronized void close() {
    if (database != null)
        database.close ();
    super.close ();
}

@Override
public void onCreate(SQLiteDatabase db) {

    }

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (newVersion > oldVersion)
        try {
            copyDataBase ();
        } catch (IOException e) {
            e.printStackTrace ();
        }
}

public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
    return database.query ("fradeu", null, null, null, null, null,null);

    }
}

XML-файл, используемый для SimpleCursorAdapter:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    <TextView
        android:id="@+id/fra"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="fra"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    <TextView
        android:id="@+id/deu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="deu"
        android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

1 Ответ

0 голосов
/ 12 июня 2018

Существует множество потенциальных проблем. Вот немного контрольного списка, с которого нужно начать: -

  1. Существует ли файл mydatabase2.db в ???? / App / Main / assets папка?
  2. Это действительная база данных SQLite (откройте ее в SQlite Tool и проверьте).
  3. Таблица fradeu должнаиметь столбец с именем _id, который должен быть псевдонимом rowid (например, он определен как _id INTEGER PRIMARY KEY или _id INTEGER PRIMARY AUTOINCREMENT, , последний не рекомендуется из-за ненужных издержек )
    • Примечание: обратитесь к коду, который устанавливает allColumns (и как вы можете обойтись без столбца _id ).

Исправление

Чтобы преодолеть проблему, код был довольно сильно изменен, включая код для выявления потенциальных проблем, поэтому он немного раздутый и вместо того, чтобы распространять исключения, требующие предложений try / catch на более высоких уровнях, для которых они тестируются, изахвачено на нижнем уровне (для моего удобства).

из рабочего кода (как показано ниже) в качестве mydatabase3.db используется следующее: -

enter image description here

, которое было скопировано в папку ресурсов.

Результирующее приложение изначально выглядит так: -

enter image description here

А затем: -

enter image description here

Код

  • Примечание. См. Комментарии для исправлений, рекомендации и причины изменений

DatabaseHelper.java : -

public class DatabaseHelper extends SQLiteOpenHelper {

    private String DB_PATH = null;
    private static String DB_NAME = "mydatabase3.db";
    private SQLiteDatabase database;
    private final Context myContext;
    public static final String TABLE_NAME = "fradeu";
    public static final String COL1 = "fra";
    public static final String COL2 = "deu";

    public DatabaseHelper(Context context) {
        super (context, DB_NAME, null, 10);
        this.myContext = context;
        this.DB_PATH = "/data/data/" + context.getPackageName () + "/" + "databases/";
        String altdbpath = (context.getDatabasePath("anything")).getParent() + "/"; //<<<< gets path without hardcoding recommended
        //<<<< Added for info re paths
        Log.d("DBPATHINFO","Hardcoded DB path is >>>>" + DB_PATH + "<<<<");
        Log.d("DBPATHINFO","Derived   DB path is >>>>" + altdbpath + "<<<<");
        Log.e ("Path 1", DB_PATH);
    }

    public void createDataBase() {
        boolean dbExist = checkDataBase ();
        if (!dbExist) {
            this.getReadableDatabase ();
            copyDataBase();
        }
    }

    // Note can check file which won't issue stacktrace which may be confusing
    private boolean checkDataBase() {
        SQLiteDatabase checkDB = null;
        try {
            String myPath = DB_PATH + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
        } catch (SQLiteException e) {
        }
        if (checkDB != null) {
            checkDB.close ();
        }
        return checkDB != null;
    }


    private void copyDataBase() {

        InputStream myInput;
        OutputStream myOutput;

        final String TAG = "COPYDATABASE";
        Log.d(TAG,"Attempt to copy database initiated.");
        Log.d(TAG,"Attempting to open Asset " + DB_NAME);
        try {
            myInput = myContext.getAssets().open(DB_NAME);
        } catch (IOException e) {
            Log.d(TAG,"Error attempting to open Asset " +DB_NAME);
            throw new RuntimeException(e);
        }
        //InputStream myInput = myContext.getAssets ().open (DB_NAME);
        String outFileName = DB_PATH + DB_NAME;
        Log.d(TAG,"Attempting to open the Database file :- " + outFileName);
        try {
            myOutput = new FileOutputStream(outFileName);
        } catch (IOException e) {
            Log.d(TAG,"Error attempting to open the Database file :-" + outFileName);
            throw new RuntimeException(e);
        }
        byte[] buffer = new byte[4096];
        long bytescopied = 0;
        int length;
        Log.d(TAG,"Attempting to copy from the asset file to the Database file");
        try {
            while ((length = myInput.read(buffer)) > 0) {
                myOutput.write(buffer, 0, length);
                bytescopied = bytescopied + length;
            }
        } catch (IOException e) {
            Log.d(TAG,"Error while copying from the asset file to the Database file - " +
                    String.valueOf(bytescopied) +
                    " bytes copied, so far.");
        }
        Log.d(TAG,"File has been copied from the assets file to the Database file." +
                String.valueOf(bytescopied) +
                " bytes were copied."
        );
        Log.d(TAG, "Attempting to flush and close files.");
        try {
            myOutput.flush();
            myOutput.close();
            myInput.close();
        } catch (IOException e) {
            Log.d(TAG,"Error flusing or closing files.");
        }
    }

    public void openDataBase() {
        String myPath = DB_PATH + DB_NAME;
        database = SQLiteDatabase.openDatabase (myPath, null, SQLiteDatabase.OPEN_READONLY);
    }

    public Cursor readData(){


        // String[] allColumns = new String[] {DatabaseHelper.COL1,DatabaseHelper.COL2};
        //<<<<< for a CursorAdapater _id column MUST be included
        // Assuming you have an _id column then  allColumns replaced with null (all columns)

        // Alternaelty if the table doesn have _id column then you could use :-
        //String[] allColumns = new String[] {DatabaseHelper.COL1,DatabaseHelper.COL2,"rowid AS _id"};
        Cursor c =database.query (DatabaseHelper.TABLE_NAME,null,null,null,null,null,null);
        //<<<< useless code cursor WILL NOT be null
        //      (very rarely would a cursor be null and
        //      probably only if trapped by try/catch
        //          which will tend to obfuscate matters/issues
        //      )
        /*
        if(c != null) {
            c.moveToFirst ();
        }
        */
        return c;
    }

    @Override
    public synchronized void close() {
        if (database != null)
            database.close ();
        super.close ();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
            copyDataBase();
    }

    public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
        return database.query ("fradeu", null, null, null, null, null,null);

    }
}

Метод onCreateView для фрагмента : -

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        //<<<< Obviously change to use your layout (this is stock layout)
        View rootView = inflater.inflate(R.layout.fragment_so50804849, container, false);
        listView = (ListView) rootView.findViewById(R.id.list); //<<<< ADDED NOTE use your id
        buttondisplay = (Button) rootView.findViewById(R.id.showlist); //<<<< ADDED NOTE use your id

        DatabaseHelper myDbHelper = new DatabaseHelper (getActivity ());
        myDbHelper.createDataBase();
        myDbHelper.openDataBase();

        /*
        c = myDbHelper.query(DatabaseHelper.TABLE_NAME,null,null,null,null,null,null);
        Cursor c = myDbHelper.readData(); //???? two cursors called c c will now refer to this one
        */
        c = myDbHelper.readData(); //<<<< Just the one cursor

        String[] from = new String []{DatabaseHelper.COL1,DatabaseHelper.COL2};
        int[] to = new int[] {R.id.fra, R.id.deu};
        adapter = new SimpleCursorAdapter(getActivity(),R.layout.list_view_adapter,c,from,to,0);
        //listView.setAdapter(adapter);

        //<<<< No need for a button see commented out line above where setAdapter is used this works
        buttondisplay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (buttondisplay.getText().toString().contains("SHOW")) {
                    listView.setAdapter(adapter);
                    buttondisplay.setText("HIDE LIST");
                } else {
                    listView.setAdapter(null);
                    buttondisplay.setText("SHOW LIST");
                }
            }
        });
        return rootView;
    }
...