我的应用似乎停止了。我无法弄清楚我的错误

时间:2017-11-11 21:38:12

标签: android android-studio android-sqlite

我的数据库是newtable,表名是First。列是Name和Id。 当我的数据库和表名相同时,我可以访问数据库,但当我有另一个具有不同名称的表时,我无法访问它。 我只想在我的数据库中显示id为1的名称。 当我在手机中执行它时,它显示应用程序一直停止。

这是我的MainActivity.java

public class MainActivity extends AppCompatActivity {
    SQLiteDatabase db;
    Random rand=new Random();
    int a=1;
    String selectQuery="select Name from First where Id="+a+";";    //Cursor c = db.rawQuery(selectQuery,null);//????????
    Cursor c;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (!CopyDBFromAssets.createDataBase(this, DB_NAME)) {
            // handle unable to create/copy DB here
        } else {
            Log.d("MAINDBCOPY", "DB copied from assets.");
        }

        ((Button) findViewById(R.id.button01)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DatabaseHelper myDbHelper = new DatabaseHelper(MainActivity.this);
                db = myDbHelper.getWritableDatabase();
                Cursor c = db.rawQuery(selectQuery,null);
                Toast.makeText(MainActivity.this, "Successfully Imported", Toast.LENGTH_SHORT).show();

                if (c.moveToFirst()) {
                    do {
                        TextView tvt=(TextView)findViewById(R.id.newtext);
                        String s=c.getString(0);
                        tvt.setText(s);
                    } while (c.moveToNext());
                }
            }
        });
    }
}

这是我的DatabaseHelper类文件

public class DatabaseHelper extends SQLiteOpenHelper {
String DB_PATH = null;
public static final String DB_NAME = "newtable.db";
private SQLiteDatabase myDataBase;
private final Context myContext;
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);
}
@Override
public void onCreate(SQLiteDatabase db) {
    Log.d("DBHELPER","onCreate Invoked");
}
@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 myDataBase.query("First", null, null, null, null, null, null);
}
}

这是CopyDBFromAssests 公共类CopyDBFromAssets {

boolean copied = false;

public static boolean createDataBase(Context context, String databasename) {

    boolean copied = false;

    boolean dbExist = checkDataBase(context, databasename);

    if(!dbExist) {

        // calling this method will create an empty database
        // which will hopefully be overidden, if not then
        // empty database will exist ?????????
        //this.getReadableDatabase(); <<<<< NOTE Commented out as empty db with no tables is useless

        if (!checkAssetExists(context, databasename, "")) {
            Log.e("CREATEDB", "Error getting asset " + databasename);
        } else {
            return copyDataBase(context, databasename);
        }
        return false;
    }
    return true;
}


private static boolean checkAssetExists(Context context, String assetfile, String path) {
    boolean rv = false;     // assume asset file doesn't exist
    String[] assetsfound = new String[]{};
    // Get the list of assets at the given path

    try {
        assetsfound = context.getAssets().list(path);
    } catch (IOException e) {
        Log.e("CHECKASSET","IO Exception when checking for the asset file." + e.getMessage());
        return false;
    }
    // Check to see if the desired asset (passed assetfile) exists
    for (String s: assetsfound) {
        if (s.equals(assetfile)) {
            rv = true;
            break;
        }
    }
    if (rv) {
        Log.d("CHECKASSET", "Asset " + assetfile + " was found.");
    } else {
        String assetlist = "";
        for (String s: assetsfound) {
            assetlist = assetlist + " " + s;
        }
        Log.e("CHECKASSET", "Asset " + assetfile +
                "could not be found. Assets that exists are:- " +
                assetlist
        );
    }
    // Asset not found lets try ignoring case
    if (!rv) {
        for (String s: assetsfound) {
            if ((s.toLowerCase()).equals(assetfile.toLowerCase())) {
                Log.e("CHECKASSET","Found asset as " + assetfile +
                        " but looking for " + s +
                        ", although they are similar the case is different."
                );
            }
        }
    }
    return rv;
}

这是堆栈跟踪。

11-16 17:38:07.551 32220-32220/com.example.darshil.dbchecking E/AndroidRuntime: FATAL EXCEPTION: main
                                                                            Process: com.example.darshil.dbchecking, PID: 32220
                                                                            android.database.sqlite.SQLiteException: no such table: First (code 1): , while compiling: select Name from First where Id=1;
                                                                                at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
                                                                                at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
                                                                                at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
                                                                                at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
                                                                                at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
                                                                                at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
                                                                                at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
                                                                                at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1318)
                                                                                at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1257)
                                                                                at com.example.darshil.dbchecking.MainActivity$1.onClick(MainActivity.java:40)
                                                                                at android.view.View.performClick(View.java:5612)
                                                                                at android.view.View$PerformClick.run(View.java:22285)
                                                                                at android.os.Handler.handleCallback(Handler.java:751)
                                                                                at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                at android.os.Looper.loop(Looper.java:154)
                                                                                at android.app.ActivityThread.main(ActivityThread.java:6123)
                                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
                                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
11-16 17:38:07.553 1601-5060/? W/ActivityManager:   Force finishing activity com.example.darshil.dbchecking/.MainActivity
11-16 17:38:07.572 1601-1626/? E/ActivityManager: Sending non-protected broadcast com.motorola.motocare.INTENT_TRIGGER from system 
4246:com.motorola.process.system/1000 pkg com.motorola.motgeofencesvc

java.lang.Throwable
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18226)
                                                  at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:18826)
                                                  at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:512)
                                                  at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2906)
                                                  at android.os.Binder.execTransact(Binder.java:565)
java.lang.Throwable
                                                  at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18226)
                                                  at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:18826)
                                                  at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:512)
                                                  at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2906)
                                                  at android.os.Binder.execTransact(Binder.java:565)

1 个答案:

答案 0 :(得分:1)

有很多问题,例如

  • 使用以下行: -

    • SQLiteDatabase db = SQLiteDatabase.openDatabase("/data/data/com.package.name/databases/dbname.db", null, SQLiteDatabase.OPEN_READWRITE);
    • Cursor c = db.rawQuery(selectQuery,null);
  • 尝试使用DBHelper复制数据库文件,这将创建一个数据库。

以下是这些问题的解决方案,当newtable.db中存在名为 PATH_TO_YOUR_PROJECT\YOURPACKAGE\app\src\main\assets 的文件时: -

  • 有效的SQLite数据库。
  • 有一个名为newtable的表,其中包含: -
    • 名为 Id
    • 的列
    • 名为名称
    • 的列

该解决方案包含了一个我称为CopyDbFromAssets的新类,MainActivity中的一些额外行。还有一些注释掉的行是多余的,或者会导致MainActivity.javaDatabaseHelper.java

中出现问题

CopyDBFromAssets.java: -

public class CopyDBFromAssets {

    boolean copied = false;

    public static boolean createDataBase(Context context, String databasename) {

        boolean copied = false;

        boolean dbExist = checkDataBase(context, databasename);

        if(!dbExist) {

            // calling this method will create an empty database
            // which will hopefully be overidden, if not then
            // empty database will exist ?????????
            //this.getReadableDatabase(); <<<<< NOTE Commented out as empty db with no tables is useless

            if (!checkAssetExists(context, databasename, "")) {
                Log.e("CREATEDB", "Error getting asset " + databasename);
            } else {
                return copyDataBase(context, databasename);
            }
            return false;
        }
        return true;
    }


    private static boolean checkAssetExists(Context context, String assetfile, String path) {
        boolean rv = false;     // assume asset file doesn't exist
        String[] assetsfound = new String[]{};
        // Get the list of assets at the given path

        try {
            assetsfound = context.getAssets().list(path);
        } catch (IOException e) {
            Log.e("CHECKASSET","IO Exception when checking for the asset file." + e.getMessage());
            return false;
        }
        // Check to see if the desired asset (passed assetfile) exists
        for (String s: assetsfound) {
            if (s.equals(assetfile)) {
                rv = true;
                break;
            }
        }
        if (rv) {
            Log.d("CHECKASSET", "Asset " + assetfile + " was found.");
        } else {
            String assetlist = "";
            for (String s: assetsfound) {
                assetlist = assetlist + " " + s;
            }
            Log.e("CHECKASSET", "Asset " + assetfile +
                    "could not be found. Assets that exists are:- " +
                    assetlist
            );
        }
        // Asset not found lets try ignoring case
        if (!rv) {
            for (String s: assetsfound) {
                if ((s.toLowerCase()).equals(assetfile.toLowerCase())) {
                    Log.e("CHECKASSET","Found asset as " + assetfile +
                            " but looking for " + s +
                            ", although they are similar the case is different."
                    );
                }
            }
        }
        return rv;
    }

    // check if database exists to avoid recopying it
    private static boolean checkDataBase (Context context, String database){
        SQLiteDatabase checkDB = null;
        String dbpath = context.getDatabasePath(database).getPath();
        File dbFile = context.getDatabasePath(dbpath);
        return dbFile.exists();
    }
    // copies db from local assets file, were it can be accessed and handled
    private static boolean copyDataBase(Context context, String  databasename)  {

        InputStream asset;
        OutputStream db;
        int bytescopied = 0;
        int length_read;
        int buffersize = 16384;
        int blockcount = 0;
        boolean rv = false;

        try {
            asset = context.getAssets().open(databasename);
        } catch (IOException e) {
            Log.e("COPYDB",
                    "IO Error opening the asset " +
                            databasename +
                            ". Error Message was " +
                            e.getMessage()
            );
            return false;
        }

        try {
            File databasesdir =  new File(context.getDatabasePath(databasename).getParent());
            databasesdir.mkdir();
            db = new FileOutputStream(context.getDatabasePath(databasename).getPath());
        }  catch (IOException e) {
            Log.e("COPYDB",
                    "IO Error opening the output file for the database with path " +
                            databasename +
                            ". error Message was " +
                            e.getMessage()
            );
            e.printStackTrace();
            try {
                asset.close();
            } catch (IOException e2) {
                Log.e("COPYDB",
                        "IO Error closing the asset. Message was " + e2.getMessage()
                );
            }
            return false;
        }

        byte[] buffer = new byte[buffersize];
        try {
            while ((length_read = asset.read(buffer)) > 0) {
                db.write(buffer);
                bytescopied = bytescopied + length_read;
                blockcount++;
                rv = true;
            }
        } catch (IOException e) {
            Log.e("COPYDB",
                    "IO Error Copying Database. Bytes Copied = "
                            + bytescopied +
                            " in " +
                            blockcount +
                            " blocks of " +
                            buffersize
            );
        }
        Log.d("COPYDB","Succesfully copied Database " + databasename + " from the assets." +
                " Number of bytes copied = " + bytescopied +
                " in " + blockcount + " blocks of length " + buffersize
        );
        try {
            db.flush();
            db.close();
            asset.close();
        } catch (IOException e) {
            Log.e("COPYDB",
                    "IO Error flushing or closing Database or closing asset."
            );
        }
        return rv;
    }
}

请注意!这包括非常广泛的日志记录,应该在发布App之前将其删除。

MainActivity.java

public class MainActivity extends AppCompatActivity {
    SQLiteDatabase db;
    //SQLiteDatabase db = SQLiteDatabase.openDatabase("/data/data/com.package.name/databases/dbname.db", null, SQLiteDatabase.OPEN_READWRITE);//????????
    int a=1;
    String selectQuery="select Name from newtable where Id="+a+";";
    //Cursor c = db.rawQuery(selectQuery,null);//????????
    Cursor c;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        if (!CopyDBFromAssets.createDataBase(this, DB_NAME)) {
            // handle unable to create/copy DB here
        } else {
            Log.d("MAINDBCOPY", "DB copied from assets.");
        }

        ((Button) findViewById(R.id.button01)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DatabaseHelper myDbHelper = new DatabaseHelper(MainActivity.this);
                db = myDbHelper.getWritableDatabase();
                /*
                try {
                    myDbHelper.createDataBase();
                } catch (IOException ioe) {
                    throw new Error("Unable to create database");
                }
                try {
                    myDbHelper.openDataBase();
                } catch (SQLException sqle) {
                    throw sqle;
                }
                */
                Cursor c = db.rawQuery(selectQuery,null);
                Toast.makeText(MainActivity.this, "Successfully Imported", Toast.LENGTH_SHORT).show();

                if (c.moveToFirst()) {
                    do {
                        TextView tvt=(TextView)findViewById(R.id.newtext);
                        String s=c.getString(0);
                        tvt.setText(s);
                    } while (c.moveToNext());
                }
            }
        });
    }
}

DatabaseHelper.java: -

public class DatabaseHelper extends SQLiteOpenHelper {
    String DB_PATH = null;
    public static final String DB_NAME = "newtable.db";
    private SQLiteDatabase myDataBase;
    private final Context myContext;
    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;
        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) {
        Log.d("DBHELPER","onCreate Invoked");
    }
    @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 myDataBase.query("newtable", null, null, null, null, null, null);
    }
}

测试结果

首次运行(在正确的资产位置使用newtable.db并正确创建)

首次运行上述内容应导致: -

包含类似于以下内容的日志: -

11-12 16:39:58.503 5289-5289/mjt.myapplication D/CHECKASSET: Asset newtable.db was found.
11-12 16:39:58.504 5289-5289/mjt.myapplication D/COPYDB: Succesfully copied Database newtable.db from the assets. Number of bytes copied = 65536 in 4 blocks of length 16384
11-12 16:39:58.504 5289-5289/mjt.myapplication D/MAINDBCOPY: DB copied from assets.

后续运行

这些应该将以下内容输出到日志中: -

11-12 16:50:17.365 5394-5394/? D/MAINDBCOPY: DB copied from assets.

如果资产文件不是newtable.db(在此测试中重命名为nEwTable.db)(并且数据库尚不存在),则运行

将产生以下输出或类似结果: -

11-12 16:56:47.313 5631-5631/mjt.myapplication E/CHECKASSET: Asset newtable.dbcould not be found. Assets that exists are:-  images sounds webkit
11-12 16:56:47.313 5631-5631/mjt.myapplication E/CREATEDB: Error getting asset newtable.db

编辑后续问题

  

我已经更新了这个问题。希望你能帮帮我

问题由android.database.sqlite.SQLiteException: no such table: First (code 1): , while compiling: select Name from First where Id=1;

描述

即。数据库中没有名为 First 的表。

String selectQuery="select Name from First where Id="+a+";";定义表名,即从第一个 ....中选择名称。

这一行由Cursor c = db.rawQuery(selectQuery,null);行调用 根据堆栈跟踪线: -

at com.example.darshil.dbchecking.MainActivity$1.onClick(MainActivity.java:40)

出于某种原因,假设数据库已成功复制,即日志包含以下行: -

D/MAINDBCOPY: DB copied from assets.

然后数据库的结构不包括名为 First 的表。

我建议您执行以下操作以确定哪些表存在以及表中包含哪些列(如果有): -

1)将以下两种方法复制到DatabaseHelper类文件中: -

/**
 * Log Database table Information
 */
public void logDatabaseTableInformation() {
    final String LOGTAG = "DBINFO";
    SQLiteDatabase db = this.getWritableDatabase();

    Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " initiated.");
    String mastertable = "sqlite_master";
    String typecolumn = "type";
    String namecolumn = "name";
    String sqlcolumn = "sql";
    String[] args = new String[]{"table","android_metadata"};
    Cursor csr = db.query(mastertable,
            null,
            typecolumn + "=? AND " + namecolumn + "!=?",
            args,
            null,null,null
    );
    while (csr.moveToNext()) {
        Log.d(LOGTAG,"Database contains Table " +
                csr.getString(csr.getColumnIndex(namecolumn)) +
                " created by SQL " +
                csr.getString(csr.getColumnIndex(sqlcolumn))
        );
        logTableInformation(csr.getString(csr.getColumnIndex(namecolumn)));
    }
    csr.close();
    Log.d(LOGTAG,new Object(){}.getClass().getEnclosingMethod().getName() + " completed.");
}

private void logTableInformation(String table) {

    final String LOGTAG = "DBINFO";
    SQLiteDatabase db = this.getWritableDatabase();

    Cursor csr = db.query(table,null,null,null,null,null,null);
    Log.d(LOGTAG,"Table is " + table +
            " Column Count = " + Integer.toString(csr.getColumnCount()) +
            " Row Count = " + Long.toString(DatabaseUtils.queryNumEntries(db,table))
    );
    StringBuilder columns_as_string = new StringBuilder();
    for (String s: csr.getColumnNames()) {
        columns_as_string.append(s + " ");
    }
    Log.d(LOGTAG, "\tColumns are :- " + columns_as_string);
    csr.close();
}
  • 第一个将数据库中的所有表输出到日志中,它还将调用第二个方法,该方法将表信息输出到日志中。稍后会详细介绍。

2)在行myDbHelper.logDatabaseTableInformation();

之后添加行DatabaseHelper myDbHelper = new DatabaseHelper(MainActivity.this);
  • 这将调用添加的方法。

3)通过设置清除应用程序的数据或卸载应用程序。

4)运行应用程序并单击按钮。

  • 请注意,您仍会收到错误,但日志应包含以下内容的额外信息: -

    11-17 06:55:26.386 2596-2596/mjt.myapplication D/CHECKASSET: Asset newtable.db was found. 11-17 06:55:26.386 2596-2596/mjt.myapplication D/COPYDB: Succesfully copied Database newtable.db from the assets. Number of bytes copied = 65536 in 4 blocks of length 16384 11-17 06:55:26.386 2596-2596/mjt.myapplication D/MAINDBCOPY: DB copied from assets.

...

11-17 06:55:39.487 2596-2596/mjt.myapplication D/DBHELPER: onCreate Invoked
11-17 06:55:39.491 2596-2596/mjt.myapplication D/DBINFO: logDatabaseTableInformation initiated.
11-17 06:55:39.491 2596-2596/mjt.myapplication D/DBINFO: Database contains Table newtable created by SQL CREATE TABLE newtable (Id INTEGER PRIMARY KEY, Name TEXT)
11-17 06:55:39.492 2596-2596/mjt.myapplication D/DBINFO: Table is newtable Column Count = 2 Row Count = 1
11-17 06:55:39.492 2596-2596/mjt.myapplication D/DBINFO:    Columns are :- Id Name 
11-17 06:55:39.492 2596-2596/mjt.myapplication D/DBINFO: logDatabaseTableInformation completed.

后一个Block显示有1个表,它被称为newtable,有2列1行。这些列名为Id和Name,表是使用SQL CREATE TABLE newtable (Id INTEGER PRIMARY KEY, Name TEXT)创建的。

您的信息可能包含不同的信息。如果有任何以 sqllite_ 开头的表名,您可以忽略它们。

假设输出如上,并且表名为 newtable ,那么您必须进行以下更改

String selectQuery="select Name from First where Id="+a+";";

MainActivity

中的

String selectQuery="select Name from newtable where Id="+a+";";

5)如果日志显示表格,则更改

String selectQuery="select Name from First where Id="+a+";";  根据你在日志中的发现。

6)如果日志没有显示任何表信息,那么您的问题是您没有删除App的数据(因此数据库可能以其初始形式存在而没有任何表)或者数据库文件被复制到资产文件夹不完整。

  • 请注意,这假设日志包含D/MAINDBCOPY: DB copied from assets.