簡體   English   中英

Android應用程序在復制數據庫時崩潰

[英]Android app crashing while copying database

我有一個運行良好的應用程序。 我必須更新數據庫,這需要刪除數據庫並重建數據庫。 我刪除數據庫就好了。 但是,我無法讀取和重建新數據庫。 錯誤日志如下:

08-28 13:03:33.932  32378-32378/com.bkane56.practice.practiceapp D/AndroidRuntime﹕ Shutting down VM
08-28 13:03:33.933  32378-32378/com.bkane56.practice.practiceapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.bkane56.practice.practiceapp, PID: 32378
    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.bkane56.practice.practiceapp/com.bkane56.practice.practiceapp.ListStopsActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)' on a null object reference
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2250)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413)
            at android.app.ActivityThread.access$800(ActivityThread.java:155)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5356)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android.database.DatabaseErrorHandler)' on a null object reference
            at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:268)
            at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
            at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:187)
            at com.bkane56.practice.practiceapp.MetroLinkDatabaseHelper.createdatabase(MetroLinkDatabaseHelper.java:67)
            at com.bkane56.practice.practiceapp.MetroLinkDatabaseHelper.<init>(MetroLinkDatabaseHelper.java:54)
            at com.bkane56.practice.practiceapp.MetroLinkDatabaseHelper.getInstance(MetroLinkDatabaseHelper.java:40)
            at com.bkane56.practice.practiceapp.ListStopsActivity.<init>(ListStopsActivity.java:27)
            at java.lang.reflect.Constructor.newInstance(Native Method)
            at java.lang.Class.newInstance(Class.java:1606)
            at android.app.Instrumentation.newActivity(Instrumentation.java:1089)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2240)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413)
            at android.app.ActivityThread.access$800(ActivityThread.java:155)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5356)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)

該問題出現在數據庫幫助器中(在Debug上崩潰)。 如下:

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;


public class MetroLinkDatabaseHelper extends SQLiteOpenHelper {

    private Context mycontext;
    private String stopName;
    private String sqlQueryTimes;
    private String sqlQueryDepart;
    private static MetroLinkDatabaseHelper myInstance;

    private static String DB_PATH = "data/data/com.bkane56.practice.practiceapp/databases/";
    private static String DB_NAME = "metrolink2.db";
    public static SQLiteDatabase myDataBase;


    public static synchronized MetroLinkDatabaseHelper getInstance(Context context) {

//        Using a singleton to minmize the chance of opening multiple
//        decreasing any chance of memory leak
        if(myInstance == null) {
            myInstance = new MetroLinkDatabaseHelper(context);
        }
        return myInstance;
    }


    private MetroLinkDatabaseHelper(Context context) {
        super(context, DB_NAME, null, 1);
        this.mycontext = context;
        boolean dbexist = checkdatabase();
        if (dbexist) {
        } else {
            System.out.println("Database doesn't exist");
            try {
                createdatabase();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    //      Create (copy the original in assets) if not exist using copydatabase
    public void createdatabase() throws IOException {
        boolean dbexist = checkdatabase();
        if (dbexist) {
        } else {
            this.getReadableDatabase();
            try {
                copydatabase();
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }
    }

    //     Check if the Android database has been created from attached database
    private boolean checkdatabase() {
        boolean checkdb = false;
        try {
            String myPath = DB_PATH + DB_NAME;
            File dbfile = new File(myPath);
            checkdb = dbfile.exists();
            if (!checkdb) {
                System.out.println("THE DATA BASE DOES NOT EXIST");
            }
        } catch (SQLiteException e) {
            System.out.println("Database doesn't exist");
        }

        return checkdb;
    }

    //    copies the data from the metroLink db in assets to data/data....metrolink.db
    public void copydatabase() throws IOException {

        // Open your local db as the input stream
        InputStream myinput = mycontext.getAssets().open(DB_NAME);
        String outfilename = DB_PATH + DB_NAME;

        // Open the empty db as the output stream
        OutputStream myoutput = new FileOutputStream(outfilename);

        // buffered reader to write new database
        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 static SQLiteDatabase open() {
        // Open the database
        String mypath = DB_PATH + DB_NAME;
        myDataBase = SQLiteDatabase.openDatabase(mypath, null,
                SQLiteDatabase.OPEN_READONLY);
        return myDataBase;
    }

    public synchronized void close() {
        super.close();
        myDataBase.close();

    }

    public void delete() {
        //Delete Existing Database
        File mypath = new File(DB_PATH + DB_NAME);
        myDataBase.close();
        System.out.println("DELETING THE EXISTING DATABASE");
        myDataBase.deleteDatabase(mypath);
    }

當我調試時,它會到達:

this.getReadableDatabase();

行,然后跳回到getInstance,然后下一步使整件事崩潰。

我不認為它在listStopsActivity中,但無論如何我都會將其包括在內:

package com.bkane56.practice.practiceapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TextClock;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;


public class ListStopsActivity extends Activity {

    private Spinner lvMetroStop;
    private MetroLinkDatabaseHelper myHelper =
            MetroLinkDatabaseHelper.getInstance(this);
    private String routeColor;
    private String direction;
    private String stop;
    private ListView stopTimes;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_stops);

        populateStopsDb();

    }

    private void openDB() {

      myHelper.open();
    }

    private void closeDB() {
        myHelper.close();
    }


    private void populateStopsDb() {

        lvMetroStop = (Spinner) findViewById(R.id.metroStopList);
        List<String> metroStop = myHelper.getAllStops();

        // Create ArrayAdapter using the planet list.
        ArrayAdapter<String> listAdapter = new ArrayAdapter<>(this, R.layout.simplerow, metroStop);
        lvMetroStop.setAdapter(listAdapter);
    }

    public void populateTimesDB() {

        String dateTime = (new SimpleDateFormat("EEEE HH:mm:ss").format(Calendar.getInstance().getTime()));
        String[] dayTime = dateTime.split(" ");
        String weekDay = dayTime[0];
        String time = dayTime[1];

        String query = "SELECT st.arrival_time FROM routes r" +
                " JOIN trips t on t.route_id = r.route_id JOIN calendar c on c.service_id =t.service_id" +
                " JOIN stop_times st on st.trip_id = t.trip_id JOIN stops s on s.stop_id = st.stop_id" +
                " WHERE r.route_id LIKE \"12594" + routeColor + "\" AND s.stop_name LIKE \"" + stop +
                "\" AND t.direction_id = \"" + direction + "\" AND st.arrival_time >= \"" + time +
                "\" AND c." + weekDay + " = 1 ORDER BY st.arrival_time LIMIT 3;";

        stopTimes = (ListView) findViewById(R.id.lvStopTimes);
        List<String> metroStopTimes = myHelper.getStopTimes(query);

        // Create ArrayAdapter using the planet list.
        ArrayAdapter<String> listAdapter = new ArrayAdapter<>(this,
                R.layout.stop_time, metroStopTimes);
        stopTimes.setAdapter(listAdapter);

    }

    public void getStopName(View view) {

        lvMetroStop = (Spinner) findViewById(R.id.metroStopList);
        stopTimes = (ListView) findViewById(R.id.lvStopTimes);
        TextView stopName = (TextView) findViewById(R.id.tvStopVar);
        Button getStop = (Button) findViewById(R.id.btnGetTimest);
        TextClock myClock = (TextClock) findViewById(R.id.textClock);
        TextView thisStop = (TextView) findViewById(R.id.stop_time);
        Button reset = (Button) findViewById(R.id.btnGetNew);
        TextView header = (TextView) findViewById(R.id.open_stops_header);
        RadioGroup eastWest = (RadioGroup) findViewById(R.id.rgEastWest);
        RadioGroup redBule = (RadioGroup) findViewById(R.id.rgRedBlue);
        TextView blueRed = (TextView) findViewById(R.id.tvRouteColor);
        TextView westEast = (TextView) findViewById(R.id.tvDirection);
        RadioButton red = (RadioButton) findViewById(R.id.rbRed);
        RadioButton blue = (RadioButton) findViewById(R.id.rbBlue);
        RadioButton east = (RadioButton) findViewById(R.id.rbEast);
        RadioButton west = (RadioButton) findViewById(R.id.rbWest);


        header.setText("The Next 3 Stop Times Are");

//        gets the text from the list view (spinner)
        stop = lvMetroStop.getSelectedItem().toString();
        stopName.setText(stop);

//        set Visibilities
        stopTimes.setVisibility(View.VISIBLE);
        reset.setVisibility(View.VISIBLE);
        thisStop.setVisibility(View.VISIBLE);
        stopName.setVisibility(View.VISIBLE);
        myClock.setVisibility(View.VISIBLE);
        lvMetroStop.setVisibility(View.INVISIBLE);
        getStop.setVisibility(View.INVISIBLE);
        eastWest.setVisibility(View.INVISIBLE);
        redBule.setVisibility(View.INVISIBLE);
        blueRed.setVisibility(View.INVISIBLE);
        westEast.setVisibility(View.INVISIBLE);
        header.setText("The Current Time Is:");


//        set East/West and Red/Blue
        if (red.isChecked()) {
            routeColor = "R";
        } else {
            routeColor = "B";
        }
        if (east.isChecked()) {
            direction = "0";
        } else {
            direction = "1";
        }

        populateTimesDB();

    }

    public void resetGetStopName(View view) {

        TextView stopName = (TextView) findViewById(R.id.tvStopVar);
        TextClock myClock = (TextClock) findViewById(R.id.textClock);
        Button getStop = (Button) findViewById(R.id.btnGetTimest);
        TextView thisStop = (TextView) findViewById(R.id.stop_time);
        Button reset = (Button) findViewById(R.id.btnGetNew);
        TextView header = (TextView) findViewById(R.id.open_stops_header);
        RadioGroup eastWest = (RadioGroup) findViewById(R.id.rgEastWest);
        RadioGroup redBule = (RadioGroup) findViewById(R.id.rgRedBlue);
        TextView blueRed = (TextView) findViewById(R.id.tvRouteColor);
        TextView westEast = (TextView) findViewById(R.id.tvDirection);
        stopTimes = (ListView) findViewById(R.id.lvStopTimes);

//        set the header text and change visibility
        header.setText(R.string.open_list_of_stops);
        lvMetroStop.setVisibility(View.VISIBLE);
        getStop.setVisibility(View.VISIBLE);
        eastWest.setVisibility(View.VISIBLE);
        redBule.setVisibility(View.VISIBLE);
        blueRed.setVisibility(View.VISIBLE);
        westEast.setVisibility(View.VISIBLE);
        stopName.setVisibility(View.INVISIBLE);
        myClock.setVisibility(View.INVISIBLE);
        reset.setVisibility(View.INVISIBLE);
        thisStop.setVisibility(View.INVISIBLE);
        stopTimes.setVisibility(View.INVISIBLE);
        header.setText("Choose Your Station From List");

    }

    private final String[] RED_STOPS = new String[]{
            "LAMBERT MAIN TRML METROLINK STATION",
            "LAMBERT EAST TRML METROLINK STATION",
            "NORTH HANLEY METROLINK STATION",
            "UMSL NORTH METROLINK STATION",
            "ROCK ROAD METROLINK STATION",
            "WELLSTON METROLINK STATION",
            "DELMAR METROLINK STATION",
            "MEMORIAL HOSPITAL METROLINK STATION",
            "SWANSEA METROLINK STATION",
            "BELLEVILLE METROLINK STATION",
            "COLLEGE METROLINK STATION",
            "SHILOH-SCOTT METROLINK STATION"};

    private final String[] BLUE_STOPS = new String[]{
            "RICHMOND HEIGHTS METROLINK STATION",
            "CLAYTON METROLINK STATION",
            "BRENTWOOD METROLINK STATION",
            "MAPLEWOOD METROLINK STATION",
            "SUNNEN METROLINK STATION",
            "SHREWSBURY METROLINK STATION",
            "FORSYTH METROLINK STATION",
            "UMSL SOUTH METROLINK STATION",
            "SKINKER METROLINK STATION"};


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_list_stops, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

任何建議,將不勝感激。

編輯:對不起@Lal,我簽出了另一個分支。 正確的行號67為:

this.getReadableDatabase();

我很抱歉。

感謝@CommonsWare在另一個帖子上,我得到了答案。 我在ListAllStops中的活動的onCreate之前調用MetrolinkDatabaseHelper:

private MetroLinkDatabaseHelper myHelper =
        MetroLinkDatabaseHelper.getInstance(this);

該變量需要聲明為類變量,並在super.onCreate之后分配:

謝謝@CommonsWare。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM