如何在Android Studio模拟器上启动带有SQLite数据库的APP? [英] how to launch app with SQLite darabase on Android Studio emulator?
问题描述
我正在使用Android Studio创建一个词典应用程序。我正在尝试使用SQLite数据库。
我无法在模拟器上启动它,因为我有两个问题。
- 首先,我真的不知道如何创建目录,我是这样编写的..
"mydirectory"
显示为红色,我不知道如何修复它
:-
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
DATABASE_LOCATION = "data/data/" + mContext.getPackageName() +
"/database/";
DATABASE_FULL_PATH = DATABASE_LOCATION + DATABASE_NAME;
if (!isExistingfDB()) {
try {
File dbLocation = new File (DATABASE_LOCATION);
dbLocation = mydirectory();
extractAssetsToDatabaseDirectory(DATABASE_NAME);
} catch (IOException e) {
e.printStackTrace();
}
}
mDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_FULL_PATH, null);
}
- 我尝试从我的SQLite数据库中查询数据,但它不起作用,这里的
"SELECT * FROM "
行没有显示应有的绿色。
:-
public ArrayList<String> getWord(int dicType) {
String tableName = getTableName(dicType);
String q = "SELECT * FROM " + tableName;
Cursor result = mDB.rawQuery(q, null);
ArrayList<String> source = new ArrayList<>();
while (result.moveToNext()) {
source.add(result.getString(result.getColumnIndex(COL_KEY)));
}
return source;
}
下面是SQLite数据库的结构
i just put it as image
后续故障
谢谢,我按照步骤8更改了代码,因为它看起来并不完全像它显示的那样,并且Logcat中没有SQLite错误,只是:
06-16 19:24:15.406 2925-2925/com.example.dimarozkin.diplomdict E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.dimarozkin.diplomdict, PID: 2925
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
at com.example.dimarozkin.diplomdict.MainActivity.onPrepareOptionsMenu(MainActivity.java:194)
at android.app.Activity.onPreparePanel(Activity.java:3406)
at android.support.v4.app.FragmentActivity.onPrepareOptionsPanel(FragmentActivity.java:530)
at android.support.v4.app.FragmentActivity.onPreparePanel(FragmentActivity.java:518)
at android.support.v7.view.WindowCallbackWrapper.onPreparePanel(WindowCallbackWrapper.java:98)
at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.onPreparePanel(AppCompatDelegateImplBase.java:359)
at android.support.v7.view.WindowCallbackWrapper.onPreparePanel(WindowCallbackWrapper.java:98)
at android.support.v7.app.ToolbarActionBar$ToolbarCallbackWrapper.onPreparePanel(ToolbarActionBar.java:521)
at android.support.v7.app.ToolbarActionBar.populateOptionsMenu(ToolbarActionBar.java:455)
at android.support.v7.app.ToolbarActionBar$1.run(ToolbarActionBar.java:55)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
据我所知,错误在这里
public boolean onPrepareOptionsMenu(Menu menu) {
String activeFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container).getClass().getSimpleName();
if (activeFragment.equals(BookmarkFragment.class.getSimpleName())) {
menuSettings.setVisible(false);
toolbar.findViewById(R.id.edit_search).setVisibility(View.GONE);
toolbar.setTitle("Bookmark");
} else {
menuSettings.setVisible(true);
toolbar.findViewById(R.id.edit_search).setVisibility(View.VISIBLE);
toolbar.setTitle("");
}
return true;
}
但我还是不知道如何解决它…
推荐答案
由于您遇到困难,以下是匆忙编写的教程和代码。
在SQLite工具中创建数据库和表,根据需要添加数据,然后保存。
关闭数据库,然后重新打开以检查表和数据是否符合预期。如果不匹配,请进行更改,然后重复%2,直到您确定保存的数据库匹配。
获取保存的数据库的文件名并记录它,包括文件扩展名。
如果您尚未为应用程序创建项目,请执行此操作并保存该项目。
在IDE外部导航到项目app/src/main文件夹并创建名为Assets的文件夹(如果该文件夹尚不存在)。
将数据库文件复制到Assets文件夹。
在Android Studio中打开项目。
新建一个名为DatabaseHelper的Java类,超类为SQLiteOpenHelper(将解析为
/li>android.database.sqlite.SQLiteOpenHelper
),并选中显示选择覆盖对话框复选框。然后单击确定。
它应该如下所示:-
public class DatabaseHelper extends SQLiteOpenHelper {
public Databasehelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
在
public class DatabaseHelper extends SQLiteOpenHelper {
之后添加一行作为类变量,如:-public static final String DBNAME = "my_dic.db";
- 请注意,引号内的值必须与复制到Assets文件夹中的文件名完全相同。
。
- 添加以下类变量
:-
public static final int DBVERSION = 1;
public static final String TB_BOOKMARK = "Bookmark";
public static final String COL_BOOKMARK_KEY = "key";
public static final String COL_BOOKMARK_VALUE = "value";
public static final String COL_BOOKMARK_DATE = "date";
SQLiteDatabase mDB;
- 请注意,引号中的值需要与数据库中为TB_Bookmark、Col_Bookmark_Key、Col_Bookmark_Value和Col_Bookmark_Date定义的表名/列名匹配。
- DBVERSION将是存储在数据库的USER_VERSION字段中的版本号。
- SQliteDatabase MDB是变量的声明,用于在打开SQLiteDatabase时保存它。注意:在设置它之前,它的值当前为空。
。
将Databasehelper类的构造函数从:-
公共数据库帮助程序(上下文上下文,字符串名称,SQLiteDatabase.CursorFactory Factory,int版本){ SUPER(上下文、名称、工厂、版本); )
收件人:-
public DatabaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
}
- 这样就可以只使用一个参数,即上下文来创建Databasehelper类的实例。已经定义了其他值,或者在工厂的情况下将不使用任何值,因此NULL表示这一点。
。
- 将
ifDBExists
方法添加到DatabaseHelper类以检查数据库是否存在(您只想从资产文件复制它一次)
:-
private boolean ifDBExists(Context context) {
String dbparent = context.getDatabasePath(DBNAME).getParent();
File f = context.getDatabasePath(DBNAME);
if (!f.exists()) {
Log.d("NODB MKDIRS","Database file not found, making directories."); //<<<< remove before the App goes live.
File d = new File(dbparent);
d.mkdirs();
//return false;
}
return f.exists();
}
- 除了检查数据库文件是否存在(请注意,它被假定为有效的数据库文件)外,
- 此外,如果数据库不存在,则可能是数据库目录不存在,这将在它不存在时创建它。
。
- 添加另一个方法
copyDBFromAssets
将资产文件复制到数据库
:-
private boolean copyDBFromAssets(Context context) {
Log.d("CPYDBINFO","Starting attemtpt to cop database from the assets file.");
String DBPATH = context.getDatabasePath(DBNAME).getPath();
InputStream is;
OutputStream os;
int length = 8192;
long bytes_read = 0;
long bytes_written = 0;
byte[] buffer = new byte[length];
try {
is = context.getAssets().open(DBNAME);
} catch (IOException e) {
Log.e("CPYDB FAIL - NO ASSET","Failed to open the Asset file " + DBNAME);
e.printStackTrace();
return false;
}
try {
os = new FileOutputStream(DBPATH);
} catch (IOException e) {
Log.e("CPYDB FAIL - OPENDB","Failed to open the Database File at " + DBPATH);
e.printStackTrace();
return false;
}
Log.d("CPYDBINFO","Initiating copy from asset file" + DBNAME + " to " + DBPATH);
while (length >= 8192) {
try {
length = is.read(buffer,0,length);
} catch (IOException e) {
Log.e("CPYDB FAIL - RD ASSET",
"Failed while reading in data from the Asset. " +
String.valueOf(bytes_read) +
" bytes read ssuccessfully."
);
e.printStackTrace();
return false;
}
bytes_read = bytes_read + length;
try {
os.write(buffer,0,length);
} catch (IOException e) {
Log.e("CPYDB FAIL - WR ASSET","failed while writing Database File " +
DBPATH +
". " +
String.valueOf(bytes_written) +
" bytes written successfully.");
e.printStackTrace();
return false;
}
bytes_written = bytes_written + length;
}
Log.d("CPYDBINFO",
"Read " + String.valueOf(bytes_read) + " bytes. " +
"Wrote " + String.valueOf(bytes_written) + " bytes."
);
try {
os.flush();
is.close();
os.close();
} catch (IOException e ) {
Log.e("CPYDB FAIL - FINALISING","Failed Finalising Database Copy. " +
String.valueOf(bytes_read) +
" bytes read." +
String.valueOf(bytes_written) +
" bytes written."
);
e.printStackTrace();
return false;
}
return true;
}
- 请注意,这是故意的长篇大论,因此任何失败都可以被准确地指出。
完整的DatabaseHelper类现在将为:-
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "my_dic.db"; // <<<< VERY IMPORTANT THAT THIS MATCHES DATABASE FILE NAME
public static final int DBVERSION = 1;
public static final String TB_BOOKMARK = "Bookmark";
public static final String COL_BOOKMARK_KEY = "key";
public static final String COL_BOOKMARK_VALUE = "value";
public static final String COL_BOOKMARK_DATE = "date";
SQLiteDatabase mDB;
public DatabaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
if (!ifDBExists(context)) {
if (!copyDBFromAssets(context)) {
throw new RuntimeException("Failed to Copy Database From Assets Folder");
}
}
mDB = this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
private boolean ifDBExists(Context context) {
String dbparent = context.getDatabasePath(DBNAME).getParent();
File f = context.getDatabasePath(DBNAME);
if (!f.exists()) {
Log.d("NODB MKDIRS","Database file not found, making directories.");
File d = new File(dbparent);
d.mkdirs();
//return false;
}
return f.exists();
}
private boolean copyDBFromAssets(Context context) {
Log.d("CPYDBINFO","Starting attemtpt to cop database from the assets file.");
String DBPATH = context.getDatabasePath(DBNAME).getPath();
InputStream is;
OutputStream os;
int length = 8192;
long bytes_read = 0;
long bytes_written = 0;
byte[] buffer = new byte[length];
try {
is = context.getAssets().open(DBNAME);
} catch (IOException e) {
Log.e("CPYDB FAIL - NO ASSET","Failed to open the Asset file " + DBNAME);
e.printStackTrace();
return false;
}
try {
os = new FileOutputStream(DBPATH);
} catch (IOException e) {
Log.e("CPYDB FAIL - OPENDB","Failed to open the Database File at " + DBPATH);
e.printStackTrace();
return false;
}
Log.d("CPYDBINFO","Initiating copy from asset file" + DBNAME + " to " + DBPATH);
while (length >= 8192) {
try {
length = is.read(buffer,0,length);
} catch (IOException e) {
Log.e("CPYDB FAIL - RD ASSET",
"Failed while reading in data from the Asset. " +
String.valueOf(bytes_read) +
" bytes read ssuccessfully."
);
e.printStackTrace();
return false;
}
bytes_read = bytes_read + length;
try {
os.write(buffer,0,length);
} catch (IOException e) {
Log.e("CPYDB FAIL - WR ASSET","failed while writing Database File " +
DBPATH +
". " +
String.valueOf(bytes_written) +
" bytes written successfully.");
e.printStackTrace();
return false;
}
bytes_written = bytes_written + length;
}
Log.d("CPYDBINFO",
"Read " + String.valueOf(bytes_read) + " bytes. " +
"Wrote " + String.valueOf(bytes_written) + " bytes."
);
try {
os.flush();
is.close();
os.close();
} catch (IOException e ) {
Log.e("CPYDB FAIL - FINALISING","Failed Finalising Database Copy. " +
String.valueOf(bytes_read) +
" bytes read." +
String.valueOf(bytes_written) +
" bytes written."
);
e.printStackTrace();
return false;
}
return true;
}
}
。
- 将构造函数更改为在数据库不存在时运行
copyDBFromAssets
方法(使用ifDBExists
方法)
:-
public DatabaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
if (!ifDBExists(context)) {
if (!copyDBFromAssets(context)) {
throw new RuntimeException("Failed to Copy Database From Assets Folder");
}
}
mDB = this.getWritableDatabase();
}
- 注意:如果复制数据库时出现问题,则应用程序将因
RunTimeExcpetion
问题而停止。
。
- 最后修改活动的onCreate方法(通常是主活动)以创建DatabaseHelper类的实例。然后运行该应用程序(如果该应用程序已经运行,最好在执行此操作之前删除该应用程序的数据,以防创建了一个可能为空的数据库。)
以下代码还包括一个查询,该查询将告诉您数据库中存在哪些表:-
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatabaseHelper mDBHlpr = new DatabaseHelper(this);
Cursor csr = mDBHlpr.getWritableDatabase().query(
"sqlite_master",
null,null,null,null,null,null
);
while (csr.moveToNext()) {
Log.d("DB TABLES", csr.getString(csr.getColumnIndex("name")));
}
csr.close();
}
}
基于屏幕截图和名为my_dic.db
的数据库文件。日志中的输出为:-
06-16 02:28:45.208 4467-4467/? D/NODB MKDIRS: Database file not found, making directories.
06-16 02:28:45.208 4467-4467/? D/CPYDBINFO: Starting attemtpt to cop database from the assets file.
Initiating copy from asset filemy_dic.db to /data/data/com.mydictionaryapp.mydictionaryapp/databases/my_dic.db
Read 12288 bytes. Wrote 12288 bytes.
06-16 02:28:45.224 4467-4467/? D/DB TABLES: Bookmark
sqlite_autoindex_Bookmark_1
android_metadata
- 这表示:-
- 数据库不存在,数据库目录已创建(即
data/data/<package name>/databases
) - 将12288个字节从资产文件复制到数据库文件(即已成功复制)。
- 生成的数据库有三个条目:SQLITE_MASTER表、书签表、名为Android_METADATA的表(由存储区域设置的SDK为Android设备自动创建的表)和自动生成的书签表索引。
- 数据库不存在,数据库目录已创建(即
后续问题
该对象基本上没有一个名为getClass的方法,而是需要使用片段继承的getClass方法。因此,您需要将返回的片段括在括号中。所以不是:-
String activeFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container).getClass().getSimpleName();
您可以使用:-
String activeFragment = (getSupportFragmentManager().findFragmentById(R.id.fragment_container)).getClass().getSimpleName();
或者,您可以使用:-
Fragment activeFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
与使用:-
if (activeFragment instanceOf BookmarkFragment) { ...... rest of your code
不使用if (activeFragment.equals(BookmarkFragment.class.getSimpleName())) { ......
这篇关于如何在Android Studio模拟器上启动带有SQLite数据库的APP?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!