본문 바로가기

컴퓨터

데이터베이스와 함께 애플리케이션 제공

애플리케이션에 데이터베이스가 필요하고 내장 데이터와 함께 제공되는 경우 해당 애플리케이션을 제공하는 가장 좋은 방법은 무엇입니까? 내가해야합니까:

SQLite 데이터베이스를 미리 만들고 .apk?

응용 프로그램에 SQL 명령을 포함하고 데이터베이스를 만들고 처음 사용할 때 데이터를 삽입하도록 하시겠습니까?

내가 보는 단점은 다음과 같습니다.

SQLite 버전 불일치로 인해 문제가 발생할 수 있으며 현재 데이터베이스가 어디로 가야하고 어떻게 액세스해야하는지 모르겠습니다.

장치에서 데이터베이스를 만들고 채우는 데 시간이 오래 걸릴 수 있습니다.

어떤 제안? 문제에 관한 문서에 대한 포인터는 대단히 감사하겠습니다.

기계적 인조 인간
android-sqlite
안드로이드 데이터베이스
공유 이 질문을 개선 따르다
생성 15 oct. 162016-10-15 16:29:28 ss

면도칼
1,5202골드 배지 2 개14은색 배지 14 개35청동 휘장 35 개
생성 04 feb. 092009-02-04 20:11:28 ss

헤이 키 토이 보넨
29.9k10골드 배지 10 개37은색 배지 37 개42청동 휘장 42 개
1
stackoverflow.com/questions/9109438/… – Yaqub Ahmad 2011 년 4 월 2 일 12:45
7
SQLiteAssetHelper 사용 – Richard Le Mesurier 2014 년 3 월 6 일 12:30
의견을 추가하다
15 개의 답변

208

데이터베이스 생성 및 업데이트에는 두 가지 옵션이 있습니다.

하나는 외부에서 데이터베이스를 만든 다음 프로젝트의 자산 폴더에 배치 한 다음 거기에서 전체 데이터베이스를 복사하는 것입니다. 데이터베이스에 많은 테이블과 기타 구성 요소가있는 경우 훨씬 더 빠릅니다. res / values ​​/ strings.xml 파일에서 데이터베이스 버전 번호를 변경하면 업그레이드가 트리거됩니다. 그런 다음 외부에서 새 데이터베이스를 만들고, 자산 폴더의 이전 데이터베이스를 새 데이터베이스로 바꾸고, 이전 데이터베이스를 다른 이름으로 내부 저장소에 저장하고, 새 데이터베이스를 자산 폴더에서 내부 저장소로 복사하고, 모두 전송하여 업그레이드를 수행합니다. 이전 데이터베이스 (이전에 이름이 바뀜)의 데이터를 새 데이터베이스로 복사하고 마지막으로 이전 데이터베이스를 삭제합니다. 다음을 사용하여 원래 데이터베이스를 만들 수 있습니다.SQLite Manager FireFox 플러그인 은 생성 SQL 문을 실행합니다.

다른 옵션은 SQL 파일에서 내부적으로 데이터베이스를 만드는 것입니다. 이것은 빠르지는 않지만 데이터베이스에 테이블이 몇 개만있는 경우 사용자에게 지연이 눈에 띄지 않을 수 있습니다. res / values ​​/ strings.xml 파일에서 데이터베이스 버전 번호를 변경하면 업그레이드가 트리거됩니다. 그런 다음 업그레이드 SQL 파일을 처리하여 업그레이드를 수행합니다. 데이터베이스의 데이터는 컨테이너가 제거 된 경우 (예 : 테이블 삭제)를 제외하고 변경되지 않은 상태로 유지됩니다.

아래 예는 두 방법 중 하나를 사용하는 방법을 보여줍니다.

다음은 샘플 create_database.sql 파일입니다. 내부 메소드의 경우 프로젝트의 assets 폴더에 배치하거나 SQLite Manager의 "Execute SQL"에 복사하여 외부 메소드 용 데이터베이스를 생성합니다. (참고 : Android에서 요구하는 테이블에 대한 설명을 확인하십시오.)

--Android requires a table named 'android_metadata' with a 'locale' column
CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US');
INSERT INTO "android_metadata" VALUES ('en_US');

CREATE TABLE "kitchen_table";
CREATE TABLE "coffee_table";
CREATE TABLE "pool_table";
CREATE TABLE "dining_room_table";
CREATE TABLE "card_table";
다음은 샘플 update_database.sql 파일입니다. 내부 메소드의 경우 프로젝트의 assets 폴더에 배치하거나 SQLite Manager의 "Execute SQL"에 복사하여 외부 메소드 용 데이터베이스를 생성합니다. (참고 : 세 가지 유형의 SQL 주석은 모두 무시됩니다. 이 예제에 포함 된 SQL 구문 분석기에 의해.)

--CREATE TABLE "kitchen_table"; This is one type of comment in sql. It is ignored by parseSql.
/*

  • CREATE TABLE "coffee_table"; This is a second type of comment in sql. It is ignored by parseSql.
  • /
    {
    CREATE TABLE "pool_table"; This is a third type of comment in sql. It is ignored by parseSql.
    }
    /* CREATE TABLE "dining_room_table"; This is a second type of comment in sql. It is ignored by parseSql. */
    { CREATE TABLE "card_table"; This is a third type of comment in sql. It is ignored by parseSql. }

--DROP TABLE "picnic_table"; Uncomment this if picnic table was previously created and now is being replaced.
CREATE TABLE "picnic_table" ("plates" TEXT);
INSERT INTO "picnic_table" VALUES ('paper');
다음은 데이터베이스 버전 번호에 대해 /res/values/strings.xml 파일에 추가 할 항목입니다.

1
다음은 데이터베이스에 액세스 한 다음이를 사용하는 활동입니다. ( 참고 : 많은 리소스를 사용하는 경우 별도의 스레드에서 데이터베이스 코드를 실행할 수 있습니다. )

package android.example;

import android.app.Activity;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;

/**

  • @author Danny Remington - MacroSolve

  • Activity for demonstrating how to use a sqlite database.

  • /
    public class Database extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      DatabaseHelper myDbHelper;
      SQLiteDatabase myDb = null;
    
      myDbHelper = new DatabaseHelper(this);
      /*
       * Database must be initialized before it can be used. This will ensure
       * that the database exists and is the current version.
       */
       myDbHelper.initializeDataBase();
    
       try {
          // A reference to the database can be obtained after initialization.
          myDb = myDbHelper.getWritableDatabase();
          /*
           * Place code to use database here.
           */
       } catch (Exception ex) {
          ex.printStackTrace();
       } finally {
          try {
              myDbHelper.close();
          } catch (Exception ex) {
              ex.printStackTrace();
          } finally {
              myDb.close();
          }
      }

    }
    }
    필요한 경우 데이터베이스를 만들거나 업데이트하는 데이터베이스 도우미 클래스는 다음과 같습니다. (참고 : Android에서는 Sqlite 데이터베이스를 사용하려면 SQLiteOpenHelper를 확장하는 클래스를 만들어야합니다.)

package android.example;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

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

/**

  • @author Danny Remington - MacroSolve

  • Helper class for sqlite database.

  • /
    public class DatabaseHelper extends SQLiteOpenHelper {

    /*

    • The Android's default system path of the application database in internal

    • storage. The package of the application is part of the path of the

    • directory.

    • /
      private static String DB_DIR = "/data/data/android.example/databases/";
      private static String DB_NAME = "database.sqlite";
      private static String DB_PATH = DB_DIR + DB_NAME;
      private static String OLD_DB_PATH = DB_DIR + "old_" + DB_NAME;

      private final Context myContext;

      private boolean createDatabase = false;
      private boolean upgradeDatabase = false;

      /**

    • Constructor Takes and keeps a reference of the passed context in order to

    • access to the application assets and resources.

    • @param context

    • /
      public DatabaseHelper(Context context) {
      super(context, DB_NAME, null, context.getResources().getInteger(

            R.string.databaseVersion));

      myContext = context;
      // Get the path of the database that is based on the context.
      DB_PATH = myContext.getDatabasePath(DB_NAME).getAbsolutePath();
      }

      /**

    • Upgrade the database in internal storage if it exists but is not current.

    • Create a new empty database in internal storage if it does not exist.

    • /
      public void initializeDataBase() {
      /*

      • Creates or updates the database in internal storage if it is needed

      • before opening the database. In all cases opening the database copies

      • the database in internal storage to the cache.

      • /
        getWritableDatabase();

        if (createDatabase) {
        /*

        • If the database is created by the copy method, then the creation
        • code needs to go here. This method consists of copying the new
        • database from assets into internal storage and then caching it.
        • /
          try {
          /*
          • Write over the empty data that was created in internal
          • storage with the one in assets and then cache it.
          • /
            copyDataBase();
            } catch (IOException e) {
            throw new Error("Error copying database");
            }
            } else if (upgradeDatabase) {
            /*
        • If the database is upgraded by the copy and reload method, then
        • the upgrade code needs to go here. This method consists of
        • renaming the old database in internal storage, create an empty
        • new database in internal storage, copying the database from
        • assets to the new database in internal storage, caching the new
        • database from internal storage, loading the data from the old
        • database into the new database in the cache and then deleting the
        • old database from internal storage.
        • /
          try {
          FileHelper.copyFile(DB_PATH, OLD_DB_PATH);
          copyDataBase();
          SQLiteDatabase old_db = SQLiteDatabase.openDatabase(OLD_DB_PATH, null, SQLiteDatabase.OPEN_READWRITE);
          SQLiteDatabase new_db = SQLiteDatabase.openDatabase(DB_PATH,null, SQLiteDatabase.OPEN_READWRITE);
          /*
          • Add code to load data into the new database from the old
          • database and then delete the old database from internal
          • storage after all data has been transferred.
          • /
            } catch (IOException e) {
            throw new Error("Error copying database");
            }
            }

      }

      /**

    • 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 transfering bytestream.

    • /
      private void copyDataBase() throws IOException {
      /

      • Close SQLiteOpenHelper so it will commit the created empty database

      • to internal storage.

      • /
        close();

        /*

      • Open the database in the assets folder as the input stream.

      • /
        InputStream myInput = myContext.getAssets().open(DB_NAME);

        /*

      • Open the empty db in interal storage as the output stream.

      • /
        OutputStream myOutput = new FileOutputStream(DB_PATH);

        /*

      • Copy over the empty db in internal storage with the database in the

      • assets folder.

      • /
        FileHelper.copyFile(myInput, myOutput);

        /*

      • Access the copied database so SQLiteHelper will cache it and mark it

      • as created.

      • /
        getWritableDatabase().close();
        }

      /*

    • This is where the creation of tables and the initial population of the

    • tables should happen, if a database is being created from scratch instead

    • of being copied from the application package assets. Copying a database

    • from the application package assets to internal storage inside this

    • method will result in a corrupted database.

    • NOTE: This method is normally only called when a database has not already

    • been created. When the database has been copied, then this method is

    • called the first time a reference to the database is retrieved after the

    • database is copied since the database last cached by SQLiteOpenHelper is

    • different than the database in internal storage.

    • /
      @Override
      public void onCreate(SQLiteDatabase db) {
      /*

      • Signal that a new database needs to be copied. The copy process must

      • be performed after the database in the cache has been closed causing

      • it to be committed to internal storage. Otherwise the database in

      • internal storage will not have the same creation timestamp as the one

      • in the cache causing the database in internal storage to be marked as

      • corrupted.

      • /
        createDatabase = true;

        /*

      • This will create by reading a sql file and executing the commands in

      • it.

      • /
        // try {
        // InputStream is = myContext.getResources().getAssets().open(
        // "create_database.sql");
        //
        // String[] statements = FileHelper.parseSqlFile(is);
        //
        // for (String statement : statements) {
        // db.execSQL(statement);
        // }
        // } catch (Exception ex) {
        // ex.printStackTrace();
        // }
        }

      /**

    • Called only if version number was changed and the database has already

    • been created. Copying a database from the application package assets to

    • the internal data system inside this method will result in a corrupted

    • database in the internal data system.

    • /
      @Override
      public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      /*

      • Signal that the database needs to be upgraded for the copy method of

      • creation. The copy process must be performed after the database has

      • been opened or the database will be corrupted.

      • /
        upgradeDatabase = true;

        /*

      • Code to update the database via execution of sql statements goes

      • here.

      • /

        /*

      • This will upgrade by reading a sql file and executing the commands in

      • it.

      • /
        // try {
        // InputStream is = myContext.getResources().getAssets().open(
        // "upgrade_database.sql");
        //
        // String[] statements = FileHelper.parseSqlFile(is);
        //
        // for (String statement : statements) {
        // db.execSQL(statement);
        // }
        // } catch (Exception ex) {
        // ex.printStackTrace();
        // }
        }

      /**

    • Called everytime the database is opened by getReadableDatabase or

    • getWritableDatabase. This is called after onCreate or onUpgrade is

    • called.

    • /
      @Override
      public void onOpen(SQLiteDatabase db) {
      super.onOpen(db);
      }

      /*

    • 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.

    • /

}
다음은 파일을 복사하고 SQL 파일을 구문 분석하는 바이트 스트림 메서드를 포함하는 FileHelper 클래스입니다.

package android.example;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.channels.FileChannel;

/**

  • @author Danny Remington - MacroSolve

  • Helper class for common tasks using files.

  • /
    public class FileHelper {
    /**

    • Creates the specified toFile that is a byte for byte a copy

    • of fromFile. If toFile already existed, then

    • it will be replaced with a copy of fromFile. The name and

    • path of toFile will be that of toFile. Both

    • fromFile and toFile will be closed by this

    • operation.

    • @param fromFile

      • InputStream for the file to copy from.
    • @param toFile

      • InputStream for the file to copy to.
    • /
      public static void copyFile(InputStream fromFile, OutputStream toFile) throws IOException {
      // transfer bytes from the inputfile to the outputfile
      byte[] buffer = new byte[1024];
      int length;

      try {

        while ((length = fromFile.read(buffer)) > 0) {
            toFile.write(buffer, 0, length);
        }

      }
      // Close the streams
      finally {

        try {
            if (toFile != null) {
                try {
                    toFile.flush();
                } finally {
                    toFile.close();
                }
        }
        } finally {
            if (fromFile != null) {
                fromFile.close();
            }
        }

      }
      }

      /**

    • Creates the specified toFile that is a byte for byte a copy

    • of fromFile. If toFile already existed, then

    • it will be replaced with a copy of fromFile. The name and

    • path of toFile will be that of toFile. Both

    • fromFile and toFile will be closed by this

    • operation.

    • @param fromFile

      • String specifying the path of the file to copy from.
    • @param toFile

      • String specifying the path of the file to copy to.
    • /
      public static void copyFile(String fromFile, String toFile) throws IOException {
      copyFile(new FileInputStream(fromFile), new FileOutputStream(toFile));
      }

      /**

    • Creates the specified toFile that is a byte for byte a copy

    • of fromFile. If toFile already existed, then

    • it will be replaced with a copy of fromFile. The name and

    • path of toFile will be that of toFile. Both

    • fromFile and toFile will be closed by this

    • operation.

    • @param fromFile

      • File for the file to copy from.
    • @param toFile

      • File for the file to copy to.
    • /
      public static void copyFile(File fromFile, File toFile) throws IOException {
      copyFile(new FileInputStream(fromFile), new FileOutputStream(toFile));
      }

      /**

    • Creates the specified toFile that is a byte for byte a copy

    • of fromFile. If toFile already existed, then

    • it will be replaced with a copy of fromFile. The name and

    • path of toFile will be that of toFile. Both

    • fromFile and toFile will be closed by this

    • operation.

    • @param fromFile

      • FileInputStream for the file to copy from.
    • @param toFile

      • FileInputStream for the file to copy to.
    • /
      public static void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException {
      FileChannel fromChannel = fromFile.getChannel();
      FileChannel toChannel = toFile.getChannel();

      try {

        fromChannel.transferTo(0, fromChannel.size(), toChannel);

      } finally {

        try {
            if (fromChannel != null) {
                fromChannel.close();
            }
        } finally {
            if (toChannel != null) {
                toChannel.close();
            }
        }

      }
      }

      /**

    • Parses a file containing sql statements into a String array that contains

    • only the sql statements. Comments and white spaces in the file are not

    • parsed into the String array. Note the file must not contained malformed

    • comments and all sql statements must end with a semi-colon ";" in order

    • for the file to be parsed correctly. The sql statements in the String

    • array will not end with a semi-colon ";".

    • @param sqlFile

      • String containing the path for the file that contains sql
    • statements.

    • @return String array containing the sql statements.

    • /
      public static String[] parseSqlFile(String sqlFile) throws IOException {
      return parseSqlFile(new BufferedReader(new FileReader(sqlFile)));
      }

      /**

    • Parses a file containing sql statements into a String array that contains

    • only the sql statements. Comments and white spaces in the file are not

    • parsed into the String array. Note the file must not contained malformed

    • comments and all sql statements must end with a semi-colon ";" in order

    • for the file to be parsed correctly. The sql statements in the String

    • array will not end with a semi-colon ";".

    • @param sqlFile

      • InputStream for the file that contains sql statements.
    • @return String array containing the sql statements.

    • /
      public static String[] parseSqlFile(InputStream sqlFile) throws IOException {
      return parseSqlFile(new BufferedReader(new InputStreamReader(sqlFile)));
      }

      /**

    • Parses a file containing sql statements into a String array that contains

    • only the sql statements. Comments and white spaces in the file are not

    • parsed into the String array. Note the file must not contained malformed

    • comments and all sql statements must end with a semi-colon ";" in order

    • for the file to be parsed correctly. The sql statements in the String

    • array will not end with a semi-colon ";".

    • @param sqlFile

      • Reader for the file that contains sql statements.
    • @return String array containing the sql statements.

    • /
      public static String[] parseSqlFile(Reader sqlFile) throws IOException {
      return parseSqlFile(new BufferedReader(sqlFile));
      }

      /**

    • Parses a file containing sql statements into a String array that contains

    • only the sql statements. Comments and white spaces in the file are not

    • parsed into the String array. Note the file must not contained malformed

    • comments and all sql statements must end with a semi-colon ";" in order

    • for the file to be parsed correctly. The sql statements in the String

    • array will not end with a semi-colon ";".

    • @param sqlFile

      • BufferedReader for the file that contains sql statements.
    • @return String array containing the sql statements.

    • /
      public static String[] parseSqlFile(BufferedReader sqlFile) throws IOException {
      String line;
      StringBuilder sql = new StringBuilder();
      String multiLineComment = null;

      while ((line = sqlFile.readLine()) != null) {

        line = line.trim();
      
        // Check for start of multi-line comment
        if (multiLineComment == null) {
            // Check for first multi-line comment type
            if (line.startsWith("/*")) {
                if (!line.endsWith("}")) {
                    multiLineComment = "/*";
                }
            // Check for second multi-line comment type
            } else if (line.startsWith("{")) {
                if (!line.endsWith("}")) {
                    multiLineComment = "{";
            }
            // Append line if line is not empty or a single line comment
            } else if (!line.startsWith("--") && !line.equals("")) {
                sql.append(line);
            } // Check for matching end comment
        } else if (multiLineComment.equals("/*")) {
            if (line.endsWith("*/")) {
                multiLineComment = null;
            }
        // Check for matching end comment
        } else if (multiLineComment.equals("{")) {
            if (line.endsWith("}")) {
                multiLineComment = null;
            }
        }

      }

      sqlFile.close();

      return sql.toString().split(";");
      }

}
공유 이 답변을 개선 따르다
생성 02 feb. 112011-02-02 02:45:22 s.

오스틴 마호니
11k77 개의 금 휘장5757 개의 은색 배지8585 개의 브론즈 배지
생성 26 jan. 112011-01-26 21:22:28 s.

Danny Remington-OMS
3,804삼골드 배지 3 개2626 개의 은색 배지19청동 휘장 19 개
위의 코드를 사용하여 db "upgrade_database.sql contains insert statement. 일부 값에는 insert into table_a values ​​( 'ss', 'ddd', 'aaaa; aaa');"와 같은 세미콜론이 있습니다. 나는이 문제를 해결하는 방법에 대한 모든 ides 값의 세미 콜로 인해 삽입이 esecute되지 않는다는 것을 상기 언급했습니다. – Sam jul. 16 '11 10:48에
6
세 번째 옵션이 있습니다-웹에서 db를 복사하십시오. 나는 이것을 해왔고 4 meg db에 대해 상당히 빨리 진행됩니다. 또한 2.3에서 첫 번째 솔루션 (db 복사)이 작동하지 않는 문제를 해결합니다. – Jack BeNimble 2011 년 9 월 9 일 13:00
2
Danny And Austyn-귀하의 솔루션은 완벽했습니다. 나는 내 집에서 양조 한 솔루션에 문제가 있었고 당신의 솔루션을 우연히 발견했습니다. 정말 그 자리에 맞았습니다. 시간을내어 제공해 주셔서 감사합니다. – George Baker 2012 년 2 월 27 일 3:44
4
나는 가장 많이 투표하고 수락 한 답변 보다이 답변을 선호합니다. 한곳에 모든 정보가 있고 (이 링크 부분은 볼 수 없음) 내가 존재하지 않는 일부 Android 세부 정보 (예 : CREATE TABLE "android_metadata")를 언급했습니다. 또한 예제는 플러스로 매우 자세하게 작성되었습니다. 항상 좋은 것은 아니지만 코드 사이의 설명이 좋은 거의 복사 붙여 넣기 솔루션입니다. – Igor Čordaš '14 년 3 월 10 일 12:31
나는 같은 방법을 사용하고 있지만 한 가지 문제에 직면하고 있습니다. 우리는 기존의 모든 데이터를 이전 db 파일에서 새 db 파일로 더 쉽게 복사 할 수 있습니다. – Pankaj '15 년 3 월 25 일 4:15
표시 1 개 코멘트

131

SQLiteAssetHelper도서관이 작업은 정말 간단합니다.

gradle 종속성으로 추가하는 것은 쉽습니다 (그러나 Jar는 Ant / Eclipse에서도 사용할 수 있음). 문서와 함께 https://github.com/jgilfelt/android-sqlite-asset-helper 에서 찾을 수 있습니다.

참고 : 이 프로젝트는 위의 Github 링크에 명시된대로 더 이상 유지되지 않습니다.

문서에 설명 된대로 :

모듈의 gradle 빌드 파일에 종속성을 추가하십시오.

dependencies {
compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
}
데이터베이스를라는 하위 디렉토리의 assets 디렉토리에 복사하십시오 assets/databases. 예를 들면 :
assets/databases/my_database.db

(선택적으로 데이터베이스를 zip 파일로 압축 할 수 있습니다 assets/databases/my_database.zip. APK가 이미 전체로 압축되어 있으므로 필요하지 않습니다.)

예를 들어 클래스를 만듭니다.

public class MyDatabase extends SQLiteAssetHelper {

private static final String DATABASE_NAME = "my_database.db";
private static final int DATABASE_VERSION = 1;

public MyDatabase(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

}
공유 이 답변을 개선 따르다
생성 07 oct. 2018

그 미스터리 박스
1,998삼골드 배지 3 개18은색 배지 18 개25브론즈 배지 25 개
생성 03 Aug.

DavidEG
5,4292골드 배지 2 개2222 개의 은색 배지41브론즈 배지 41 개
android-sqlite-asset-helper.jar 다운로드에는 어떤 자격 증명이 필요합니까? – Pr38y '14 12 월 3 일 13:21
1
gradle을 사용하는 경우 종속성을 추가하기 만하면됩니다. – Suragch 2015 년 4 월 9 일 3:30
DB에서 데이터를 어떻게 얻습니까? – Machado '15 년 9 월 15 일 20:17
6
이 라이브러리는 4 년 전 마지막 업데이트로 폐기되었습니다. – 감소 활동 Feb 13 '18 at 17:35
1
라이브러리는 Android Pie를 실행하는 기기에서 앱과 충돌합니다. – mstoic '18 년 10 월 14 일 21:00
보여 3 개 의견

16

Android Studio 3.0에서 데이터베이스 파일과 함께 앱 배송
데이터베이스 파일과 함께 앱을 배송하는 것은 저에게 좋은 생각입니다. 장점은 복잡한 초기화를 수행 할 필요가 없다는 것입니다. 데이터 세트가 방대 할 경우 때때로 많은 시간이 소요됩니다.

1 단계 : 데이터베이스 파일 준비

데이터베이스 파일을 준비하십시오. .db 파일 또는 .sqlite 파일 일 수 있습니다. .sqlite 파일을 사용하는 경우 파일 확장자 이름을 변경하기 만하면됩니다. 단계는 동일합니다.

이 예에서는 testDB.db라는 파일을 준비했습니다. 다음과 같이 하나의 테이블과 일부 샘플 데이터가 있습니다. 여기에 이미지 설명 입력

2 단계 : 프로젝트로 파일 가져 오기

자산 폴더가없는 경우 생성합니다. 그런 다음 데이터베이스 파일을이 폴더에 복사하여 붙여 넣으십시오.

여기에 이미지 설명 입력

3 단계 : 파일을 앱의 데이터 폴더에 복사

추가 상호 작용을 수행하려면 데이터베이스 파일을 앱의 데이터 폴더에 복사해야합니다. 이것은 데이터베이스 파일을 복사하는 일회성 작업 (초기화)입니다. 이 코드를 여러 번 호출하면 데이터 폴더의 데이터베이스 파일이 assets 폴더의 파일로 덮어 쓰여집니다. 이 덮어 쓰기 프로세스는 나중에 앱 업데이트 중에 데이터베이스를 업데이트하려는 경우 유용합니다.

앱 업데이트 중에이 데이터베이스 파일은 앱의 데이터 폴더에서 변경되지 않습니다. 제거 만하면 삭제됩니다.

데이터베이스 파일을 /databases폴더에 복사해야 합니다. 장치 파일 탐색기를 엽니 다. data/data//위치를 입력 하세요. 위에서 언급 한 앱의 기본 데이터 폴더입니다. 그리고 기본적으로 데이터베이스 파일은이 디렉터리 아래의 데이터베이스라는 다른 폴더에 저장됩니다.

여기에 이미지 설명 입력

이제 파일 복사 프로세스는 Java가 수행하는 작업과 매우 유사합니다. 복사 붙여 넣기를 수행하려면 다음 코드를 사용하십시오. 이것은 시작 코드입니다. 또한 향후 데이터베이스 파일을 업데이트 (덮어 쓰기)하는 데 사용할 수도 있습니다.

//get context by calling "this" in activity or getActivity() in fragment
//call this if API level is lower than 17 String appDataPath = "/data/data/" + context.getPackageName() + "/databases/"
String appDataPath = context.getApplicationInfo().dataDir;

File dbFolder = new File(appDataPath + "/databases");//Make sure the /databases folder exists
dbFolder.mkdir();//This can be called multiple times.

File dbFilePath = new File(appDataPath + "/databases/testDB.db");

try {
InputStream inputStream = context.getAssets().open("testDB.db");
OutputStream outputStream = new FileOutputStream(dbFilePath);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer))>0)
{
outputStream.write(buffer, 0, length);
}
outputStream.flush();
outputStream.close();
inputStream.close();
} catch (IOException e){
//handle
}
그런 다음 폴더를 새로 고쳐 복사 프로세스를 확인하십시오.

여기에 이미지 설명 입력

4 단계 : 데이터베이스 열기 도우미 만들기

SQLiteOpenHelper연결, 닫기, 경로 등을 사용 하여에 대한 하위 클래스를 만듭니다.DatabaseOpenHelper

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseOpenHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "testDB.db";
public static final String DB_SUB_PATH = "/databases/" + DB_NAME;
private static String APP_DATA_PATH = "";
private SQLiteDatabase dataBase;
private final Context context;

public DatabaseOpenHelper(Context context){
    super(context, DB_NAME, null, 1);
    APP_DATA_PATH = context.getApplicationInfo().dataDir;
    this.context = context;
}

public boolean openDataBase() throws SQLException{
    String mPath = APP_DATA_PATH + DB_SUB_PATH;
    //Note that this method assumes that the db file is already copied in place
    dataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.OPEN_READWRITE);
    return dataBase != null;
}

@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) {
}

}
5 단계 : 데이터베이스와 상호 작용할 최상위 클래스 만들기

이것은 데이터베이스 파일을 읽고 쓰는 클래스입니다. 또한 데이터베이스의 값을 인쇄하는 샘플 쿼리가 있습니다.

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class Database {
private final Context context;
private SQLiteDatabase database;
private DatabaseOpenHelper dbHelper;

public Database(Context context){
    this.context = context;
    dbHelper = new DatabaseOpenHelper(context);
}

public Database open() throws SQLException
{
    dbHelper.openDataBase();
    dbHelper.close();
    database = dbHelper.getReadableDatabase();
    return this;
}

public void close()
{
    dbHelper.close();
}

public void test(){
    try{
        String query ="SELECT value FROM test1";
        Cursor cursor = database.rawQuery(query, null);
        if (cursor.moveToFirst()){
            do{
                String value = cursor.getString(0);
                Log.d("db", value);
            }while (cursor.moveToNext());
        }
        cursor.close();
    } catch (SQLException e) {
        //handle
    }
}

}
6 단계 : 테스트 실행

다음 코드 줄을 실행하여 코드를 테스트합니다.

Database db = new Database(context);
db.open();
db.test();
db.close();
실행 버튼을 누르고 응원하세요!

여기에 이미지 설명 입력

공유 이 답변을 개선 따르다
생성 20 jun.

커뮤니티 ♦
11은색 배지 1 개
생성 07 nov.

팡밍
19.4k4골드 배지 4 개8383 개의 은색 배지80브론즈 배지 80 개
1
초기화는 언제 완료해야합니까? 당신이 제안하는 전략은 무엇입니까? – Daniele B '18 년 8 월 14 일 10:59
의견을 추가하다

14

내 솔루션은 타사 라이브러리를 사용하지 않으며 SQLiteOpenHelper생성시 데이터베이스를 초기화하기 위해 하위 클래스에서 사용자 지정 메서드를 호출하도록 강요하지 않습니다 . 또한 데이터베이스 업그레이드도 처리합니다. 해야 할 일은 하위 클래스를 만드는 것 SQLiteOpenHelper입니다.

전제 조건 :
앱과 함께 제공 할 데이터베이스입니다. 앱에 고유 한 테이블 외에 값 이있는 속성으로 이름이 지정된 1x1 테이블을 포함해야합니다 .android_metadatalocaleen_US
하위 분류 SQLiteOpenHelper:
하위 클래스 SQLiteOpenHelper.
하위 클래스 private내에 메서드를 만듭니다 SQLiteOpenHelper. 이 메서드에는 'assets'폴더의 데이터베이스 파일에서 응용 프로그램 패키지 컨텍스트에서 만든 데이터베이스로 데이터베이스 콘텐츠를 복사하는 논리가 포함되어 있습니다.
재정 onCreate, onUpgrade 및 onOpen 방법 SQLiteOpenHelper.
충분했다. 다음은 SQLiteOpenHelper하위 클래스입니다.

public class PlanDetailsSQLiteOpenHelper extends SQLiteOpenHelper {
private static final String TAG = "SQLiteOpenHelper";

private final Context context;
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "my_custom_db";

private boolean createDb = false, upgradeDb = false;

public PlanDetailsSQLiteOpenHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    this.context = context;
}

/**
 * Copy packaged database from assets folder to the database created in the
 * application package context.
 * 
 * @param db
 *            The target database in the application package context.
 */
private void copyDatabaseFromAssets(SQLiteDatabase db) {
    Log.i(TAG, "copyDatabase");
    InputStream myInput = null;
    OutputStream myOutput = null;
    try {
        // Open db packaged as asset as the input stream
        myInput = context.getAssets().open("path/to/shipped/db/file");

        // Open the db in the application package context:
        myOutput = new FileOutputStream(db.getPath());

        // Transfer db file contents:
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.flush();

        // Set the version of the copied database to the current
        // version:
        SQLiteDatabase copiedDb = context.openOrCreateDatabase(
            DATABASE_NAME, 0, null);
        copiedDb.execSQL("PRAGMA user_version = " + DATABASE_VERSION);
        copiedDb.close();

    } catch (IOException e) {
        e.printStackTrace();
        throw new Error(TAG + " Error copying database");
    } finally {
        // Close the streams
        try {
            if (myOutput != null) {
                myOutput.close();
            }
            if (myInput != null) {
                myInput.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new Error(TAG + " Error closing streams");
        }
    }
}

@Override
public void onCreate(SQLiteDatabase db) {
    Log.i(TAG, "onCreate db");
    createDb = true;
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    Log.i(TAG, "onUpgrade db");
    upgradeDb = true;
}

@Override
public void onOpen(SQLiteDatabase db) {
    Log.i(TAG, "onOpen db");
    if (createDb) {// The db in the application package
        // context is being created.
        // So copy the contents from the db
        // file packaged in the assets
        // folder:
        createDb = false;
        copyDatabaseFromAssets(db);

    }
    if (upgradeDb) {// The db in the application package
        // context is being upgraded from a lower to a higher version.
        upgradeDb = false;
        // Your db upgrade logic here:
    }
}

}
마지막으로, 데이터베이스 연결을 얻기 위해, 단지 전화 getReadableDatabase()또는 getWritableDatabase()온 SQLiteOpenHelper서브 클래스와 데이터베이스가 존재하지 않는 경우는,하는 DB를 만드는 '자산'폴더에 지정된 파일에서 DB의 내용을 복사 처리됩니다.

간단히 말해, 메서드 SQLiteOpenHelper에서 SQL 쿼리를 사용하여 초기화 된 데이터베이스에 사용하는 것처럼 하위 클래스를 사용하여 assets 폴더에 제공된 db에 액세스 할 수 있습니다 onCreate().

공유 이 답변을 개선 따르다
생성 26 mar.

Vaishak Nair
81810은색 배지 10 개13브론즈 배지 13 개
2
이것은 외부 라이브러리가 필요없는 표준 Android API를 사용하는 가장 우아한 솔루션입니다. 참고로 android_metadata 테이블을 포함하지 않았으며 작동하며 최신 Android 버전이 자동으로 추가 할 수 있습니다. – goetzc '16 년 9 월 24 일 21:31
의견을 추가하다

8

2017 년 11 월 Google은 Room Persistence Library를 출시했습니다 .

문서에서 :

객실 지속성 라이브러리의 모든 기능 활용하면서 SQLite는 이상 추상화 계층은 유창한 데이터베이스에 액세스 할 수 있도록 제공 SQLite는 .

라이브러리는 앱을 실행하는 기기에서 앱 데이터의 캐시를 만드는 데 도움이됩니다. 앱의 단일 소스 역할을하는이 캐시를 사용하면 사용자가 인터넷에 연결되어 있는지 여부에 관계없이 앱 내에서 키 정보의 일관된 사본을 볼 수 있습니다.

Room 데이터베이스에는 데이터베이스를 처음 만들거나 열 때 콜백이 있습니다. create 콜백을 사용하여 데이터베이스를 채울 수 있습니다.

Room.databaseBuilder(context.applicationContext,
DataDatabase::class.java, "Sample.db")
// prepopulate the database after onCreate was called
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
// moving to a new thread
ioThread {
getInstance(context).dataDao()
.insert(PREPOPULATE_DATA)
}
}
})
.build()
이 블로그 게시물의 코드입니다 .

공유 이 답변을 개선 따르다
생성 25 jun.

Tanius
5,9712골드 배지 2 개33은색 배지 33 개39청동 휘장 39 개
생성 28 nov.

LordRaydenMK
11k삼골드 배지 3 개4545 개의 은색 배지52브론즈 배지 52 개
고마워, 이것은 나를 위해 일했다. 여기 자바 예제 – Jerry Sha May 16 '18 17:49
1
이미 존재하는 SQLite가 포함 된 APK를 배송하려는 경우 자산 폴더에 추가하고이 패키지 github.com/humazed/RoomAsset 을 사용하여 SQLite 파일 데이터를 새 파일로로드하는 마이그레이션을 수행 할 수 있습니다. 이렇게하면 기존 DB로 데이터 채우기를 저장할 수 있습니다. – xarlymg89 '18 년 8 월 17 일 11:01
의견을 추가하다

6

내가 본 것에서 이미 테이블 설정 및 데이터가있는 데이터베이스를 제공해야합니다. 그러나 원하는 경우 (그리고 보유한 애플리케이션 유형에 따라) "업그레이드 데이터베이스 옵션"을 허용 할 수 있습니다. 그런 다음 최신 sqlite 버전을 다운로드하고 온라인에서 호스팅되는 텍스트 파일의 최신 Insert / Create 문을 가져 와서 문을 실행하고 이전 db에서 새 db로 데이터를 전송합니다.

공유 이 답변을 개선 따르다
생성 04 feb. 092009-02-04 20:14:28 s.

Masfenix
6,64299 개의 골드 배지38은색 휘장 38 개5757 개의 브론즈 배지
6

내가 본 것에서 이미 테이블 설정과 데이터가있는 데이터베이스를 제공해야합니다. 예,하지만 어떻게해야합니까? – Rory 2011 년 11 월 16 일 19:52
의견을 추가하다

5

현재 APK와 함께 제공 할 SQLite 데이터베이스를 미리 만들 수있는 방법은 없습니다. 최선의 방법은 적절한 SQL을 리소스로 저장하고 애플리케이션에서 실행하는 것입니다. 예, 이로 인해 데이터가 중복됩니다 (동일한 정보가 리소스 및 데이터베이스로 존재 함).하지만 지금은 다른 방법이 없습니다. 유일한 완화 요소는 apk 파일이 압축된다는 것입니다. 내 경험은 908KB가 268KB 미만으로 압축됩니다.

아래 스레드에는 좋은 샘플 코드로 찾은 최고의 토론 / 솔루션이 있습니다.

http://groups.google.com/group/android-developers/msg/9f455ae93a1cf152

내 CREATE 문을 Context.getString ()으로 읽을 문자열 리소스로 저장하고 SQLiteDatabse.execSQL ()로 실행했습니다.

res / raw / inserts.sql에 삽입 데이터를 저장했습니다 (sql 파일, 7000 개 이상의 라인 생성). 위 링크의 기술을 사용하여 루프를 입력하고 파일을 한 줄씩 읽고 데이터를 "INSERT INTO tbl VALUE"에 연결하고 다른 SQLiteDatabase.execSQL ()을 수행했습니다. 7000 개의 "INSERT INTO tbl VALUE"가 단지 연결될 수있을 때 저장하는 것은 의미가 없습니다.

에뮬레이터에서 약 20 초가 걸리고 실제 전화에서 얼마나 걸릴지 모르겠지만 사용자가 처음 응용 프로그램을 시작할 때 한 번만 발생합니다.

공유 이 답변을 개선 따르다
생성 04 feb. 092009-02-04 23:32:14 s.

의지
17.1k10골드 배지 10 개38은색 휘장 38 개39청동 휘장 39 개

처음 실행할 때 웹에서 SQL 스크립트를 가져 오는 것은 어떻습니까? 이렇게하면 데이터를 복제 할 필요가 없습니다. – Tamas Czinege 2009 년 3 월 6 일 19:35
1
예,하지만 장치가 인터넷에 연결되어 있어야합니다. 이는 일부 앱의 심각한 단점입니다. – Dzhuneyt 2014 년 2 월 12 일 17:00
1
7000 개 이상의 삽입을 수행하지 말고 100 개 정도의 일괄 삽입을 수행하십시오 INSERT INTO table VALUES(...) VALUES(...) VALUES(...) ...(1 개의 삽입 행에는 100 개의 값이 있어야 함). 훨씬 더 효율적이며 시작 시간을 20 초에서 2 초 또는 3 초로 줄일 수 있습니다. – Mohit Atray 3 월 11 일 8:53
의견을 추가하다

5

드디어 해냈습니다 !! 이 링크 도움말을 Android 응용 프로그램에서 자신의 SQLite 데이터베이스 사용을 사용 했지만 약간 변경해야했습니다.

패키지가 많은 경우 여기에 마스터 패키지 이름을 입력해야합니다.

private static String DB_PATH = "data/data/masterPakageName/databases";

로컬 폴더에서 에뮬레이터 폴더로 데이터베이스를 복사하는 방법을 변경했습니다! 그 폴더가 존재하지 않았을 때 문제가있었습니다. 따라서 먼저 경로를 확인하고 경로가 없으면 폴더를 생성해야합니다.

이전 코드에서는 copyDatabase데이터베이스가 존재하지 않고 checkDataBase메서드로 인해 예외가 발생 했을 때 메서드가 호출되지 않았습니다 . 그래서 코드를 약간 변경했습니다.

데이터베이스에 파일 확장자가 없으면 파일 이름과 함께 사용하지 마십시오.

그것은 나를 위해 잘 작동합니다, 나는 그것이 당신에게도 유용하기를 바랍니다.

package farhangsarasIntroduction;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

import android.util.Log;

public class DataBaseHelper extends SQLiteOpenHelper{

//The Android's default system path of your application database.
private static String DB_PATH = "data/data/com.example.sample/databases";

private static String DB_NAME = "farhangsaraDb";

private SQLiteDatabase myDataBase;

private final Context myContext;

/**
  * Constructor
  * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
  * @param context
  */
public DataBaseHelper(Context context) {

    super(context, DB_NAME, null, 1);
        this.myContext = context;

}   

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

    boolean dbExist;
    try {

         dbExist = checkDataBase();


    } catch (SQLiteException e) {

        e.printStackTrace();
        throw new Error("database dose not exist");

    }

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

        try {

            copyDataBase();


        } catch (IOException e) {

            e.printStackTrace();
            throw new Error("Error copying database");

        }
//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();


}

}

/**
  * 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.
    throw new Error("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 transfering bytestream.
  * */
private void copyDataBase() throws IOException{



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

        // Path to the just created empty db
        String outFileName = DB_PATH +"/"+ DB_NAME;
        File databaseFile = new File( DB_PATH);
         // check if databases folder exists, if not create one and its subfolders
        if (!databaseFile.exists()){
            databaseFile.mkdir();
        }

        //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();



}



@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) {

}

 you to create adapters for your views.

}
공유 이 답변을 개선 따르다
생성 03 apr. 142014-04-03 15:01:22 ss

루이 비에이라
4,9405골드 배지 5 개37은색 배지 37 개5151 개의 브론즈 배지
생성 14 feb. 142014-02-14 09:03:22 s.

afsane
1,7995골드 배지 5 개24은색 배지 24 개40브론즈 배지 40 개
u는 나에게 내가 기존 DB를 삭제하는 방법을 새 것으로 이전 데이터베이스를 교체하려는 경우 DB를 업그레이드하는 방법을 알려 주시기 바랍니다 수 있습니다 - Erum 3월 4일 '14을 17시 9분에서
지금이 전까지 할 필요가 haven`t하지만, 새로운 응용 프로그램이 설치되어있는 경우, 새로운 DB도 교체 - afsane 6시 35분에서 3월 10일 '14
내가 애셋 폴더에 새 db를 추가하고 있기 때문에 이전 데이터베이스를 삭제하는 방법 그런 다음 지정된 폴더에서 이전 db를 어떻게 삭제합니까? 그렇지 않으면 이전 db의 내용을 가져옵니다 – Erum Mar 10 '14 at 10:31
나는 이것이 유용하길 바란다. stackoverflow.com/questions/9109438/… – afsane Mar 11 '14 at 10:50
완벽합니다, 감사합니다! 데이터베이스 확인시 예외를 던지면 DB가 처음에 존재하지 않고 예외가 throw 된 후 메서드가 계속되지 않기 때문에 하나의 주석 만 있으면 앱이 닫힙니다. 나는 단순히 throw new Error ( "database dose not exist"); 이제 모든 것이 완벽하게 작동합니다. – Grinner 2014 년 9 월 9 일 13:37
의견을 추가하다

5

클래스와 질문에 대한 답변을 수정하고 DB_VERSION을 통해 데이터베이스를 업데이트 할 수있는 클래스를 작성했습니다.

public class DatabaseHelper extends SQLiteOpenHelper {
private static String DB_NAME = "info.db";
private static String DB_PATH = "";
private static final int DB_VERSION = 1;

private SQLiteDatabase mDataBase;
private final Context mContext;
private boolean mNeedUpdate = false;

public DatabaseHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
    if (android.os.Build.VERSION.SDK_INT >= 17)
        DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
    else
        DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
    this.mContext = context;

    copyDataBase();

    this.getReadableDatabase();
}

public void updateDataBase() throws IOException {
    if (mNeedUpdate) {
        File dbFile = new File(DB_PATH + DB_NAME);
        if (dbFile.exists())
            dbFile.delete();

        copyDataBase();

        mNeedUpdate = false;
    }
}

private boolean checkDataBase() {
    File dbFile = new File(DB_PATH + DB_NAME);
    return dbFile.exists();
}

private void copyDataBase() {
    if (!checkDataBase()) {
        this.getReadableDatabase();
        this.close();
        try {
            copyDBFile();
        } catch (IOException mIOException) {
            throw new Error("ErrorCopyingDataBase");
        }
    }
}

private void copyDBFile() throws IOException {
    InputStream mInput = mContext.getAssets().open(DB_NAME);
    //InputStream mInput = mContext.getResources().openRawResource(R.raw.info);
    OutputStream mOutput = new FileOutputStream(DB_PATH + DB_NAME);
    byte[] mBuffer = new byte[1024];
    int mLength;
    while ((mLength = mInput.read(mBuffer)) > 0)
        mOutput.write(mBuffer, 0, mLength);
    mOutput.flush();
    mOutput.close();
    mInput.close();
}

public boolean openDataBase() throws SQLException {
    mDataBase = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.CREATE_IF_NECESSARY);
    return mDataBase != null;
}

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

@Override
public void onCreate(SQLiteDatabase db) {

}

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

}
수업 사용.

활동 클래스에서 변수를 선언하십시오.

private DatabaseHelper mDBHelper;
private SQLiteDatabase mDb;
onCreate 메서드에서 다음 코드를 작성합니다.

mDBHelper = new DatabaseHelper(this);

try {
mDBHelper.updateDataBase();
} catch (IOException mIOException) {
throw new Error("UnableToUpdateDatabase");
}

try {
mDb = mDBHelper.getWritableDatabase();
} catch (SQLException mSQLException) {
throw mSQLException;
}
res / raw 폴더에 데이터베이스 파일을 추가하는 경우 다음 클래스 수정을 사용하십시오.

public class DatabaseHelper extends SQLiteOpenHelper {
private static String DB_NAME = "info.db";
private static String DB_PATH = "";
private static final int DB_VERSION = 1;

private SQLiteDatabase mDataBase;
private final Context mContext;
private boolean mNeedUpdate = false;

public DatabaseHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
    if (android.os.Build.VERSION.SDK_INT >= 17)
        DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
    else
        DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
    this.mContext = context;

    copyDataBase();

    this.getReadableDatabase();
}

public void updateDataBase() throws IOException {
    if (mNeedUpdate) {
        File dbFile = new File(DB_PATH + DB_NAME);
        if (dbFile.exists())
            dbFile.delete();

        copyDataBase();

        mNeedUpdate = false;
    }
}

private boolean checkDataBase() {
    File dbFile = new File(DB_PATH + DB_NAME);
    return dbFile.exists();
}

private void copyDataBase() {
    if (!checkDataBase()) {
        this.getReadableDatabase();
        this.close();
        try {
            copyDBFile();
        } catch (IOException mIOException) {
            throw new Error("ErrorCopyingDataBase");
        }
    }
}

private void copyDBFile() throws IOException {
    //InputStream mInput = mContext.getAssets().open(DB_NAME);
    InputStream mInput = mContext.getResources().openRawResource(R.raw.info);
    OutputStream mOutput = new FileOutputStream(DB_PATH + DB_NAME);
    byte[] mBuffer = new byte[1024];
    int mLength;
    while ((mLength = mInput.read(mBuffer)) > 0)
        mOutput.write(mBuffer, 0, mLength);
    mOutput.flush();
    mOutput.close();
    mInput.close();
}

public boolean openDataBase() throws SQLException {
    mDataBase = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.CREATE_IF_NECESSARY);
    return mDataBase != null;
}

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

@Override
public void onCreate(SQLiteDatabase db) {

}

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

}
http://blog.harrix.org/article/6784

공유 이 답변을 개선 따르다
생성 07 aug. 182018-08-07 15:08:28 ss

HarshitMadhav
3,3075골드 배지 5 개30은색 배지 30 개4343 개의 브론즈 배지
생성 12 apr. 172017-04-12 17:14:49 s.

해 릭스
5172골드 배지 2 개8은색 배지 8 개16청동 휘장 16 개
의견을 추가하다

4

apk 안에 데이터베이스를 넣은 다음 복사 /data/data/...하면 데이터베이스 크기가 두 배 (1 in apk, 1 in data/data/...)가되고 apk 크기가 증가합니다 (물론). 따라서 데이터베이스가 너무 크지 않아야합니다.

공유 이 답변을 개선 따르다
생성 30 jul.

Phantômaxx
35.9k16골드 배지 16 개7777 개의 은색 배지106브론즈 배지 106 개
생성 12 aug. 122012-08-12 20:28:28 s.

Hiep
2,1611골드 배지 1 개2121 개의 은색 배지2727 개의 브론즈 배지

APK 크기가 다소 증가하지만 두 배가되지는 않습니다. 자산에있을 때 압축되어 훨씬 더 작습니다. 데이터베이스 폴더에 복사 한 후 압축이 풀립니다. – Suragch 2015-04-09 2:32
의견을 추가하다

Android는 이미 버전 인식 방식의 데이터베이스 관리를 제공합니다. 이 접근 방식은 Android 애플리케이션 용 BARACUS 프레임 워크에서 활용되었습니다.

앱의 전체 버전 수명주기에 따라 데이터베이스를 관리 할 수 ​​있으므로 이전 버전에서 현재 버전으로 sqlite 데이터베이스를 업데이트 할 수 있습니다.

또한 SQLite의 핫 백업 및 핫 복구를 실행할 수 있습니다.

100 % 확실하지는 않지만 특정 장치에 대한 핫 복구를 통해 준비된 데이터베이스를 앱에 제공 할 수 있습니다. 그러나 특정 장치, 공급 업체 또는 장치 세대에 특정한 데이터베이스 바이너리 형식에 대해 잘 모르겠습니다.

물건은 Apache License 2이므로 코드의 일부를 자유롭게 재사용 할 수 있습니다. github에서 찾을 수 있습니다.

편집하다 :

데이터 만 전달하려는 경우 애플리케이션을 처음 시작할 때 POJO를 인스턴스화하고 지속하는 것을 고려할 수 있습니다. BARACUS는 이에 대한 기본 지원을 제공합니다 (예 : "APP_FIRST_RUN"과 컨텍스트에서 실행 후 작업을 실행하기 위해 컨텍스트 이후 부트 스트랩 후크와 같은 구성 정보를위한 기본 제공 키 값 저장소). 이를 통해 밀접하게 결합 된 데이터를 앱과 함께 제공 할 수 있습니다. 대부분의 경우 이것은 내 사용 사례에 적합합니다.

공유 이 답변을 개선 따르다
생성 24 nov.
생성 28 oct. 142014-10-28 06:41:28 ss

고어 페스트
6666은색 배지 6 개19청동 휘장 19 개
의견을 추가하다

필요한 데이터가 너무 크지 않은 경우 (내가 알지 못하는 한계, 많은 사항에 따라 다름) 웹 사이트 / 웹 앱에서 데이터 (XML, JSON 등)를 다운로드 할 수도 있습니다. 수신 후 수신 된 데이터를 사용하여 테이블을 생성하고 데이터를 삽입하여 SQL 문을 실행합니다.

모바일 앱에 많은 데이터가 포함 된 경우 나중에 더 정확한 데이터 또는 변경 사항으로 설치된 앱의 데이터를 업데이트하는 것이 더 쉬울 수 있습니다.

공유 이 답변을 개선 따르다
생성 27 Aug.

알렉산더 파버
17.7k6666 개의 골드 배지205은색 배지 205 개361브론즈 배지 361 개
생성 21 dec.

자코
2492은색 배지 2 개2브론즈 배지 2 개
의견을 추가하다

이 과정을 단순화하기 위해 라이브러리 를 작성했습니다 .

dataBase = new DataBase.Builder(context, "myDb").
// setAssetsPath(). // default "databases"
// setDatabaseErrorHandler().
// setCursorFactory().
// setUpgradeCallback()
// setVersion(). // default 1
build();
assets/databases/myDb.db파일 에서 데이터베이스를 생성 합니다. 또한 이러한 모든 기능을 사용할 수 있습니다.

파일에서 데이터베이스로드
데이터베이스에 대한 동기화 된 액세스
SQLite 최신 버전의 Android 전용 배포 인 requery로 sqlite-android 를 사용 합니다.
github 에서 복제하십시오 .

공유 이 답변을 개선 따르다
생성 10 jul.

일리아 가즈 만
26.3k1717 개의 금 휘장112112 개의 은색 배지180청동 휘장 180 개
의견을 추가하다

2

나는 ORMLite를 사용하고 있으며 아래 코드가 나를 위해 일했습니다.

public class DatabaseProvider extends OrmLiteSqliteOpenHelper {
private static final String DatabaseName = "DatabaseName";
private static final int DatabaseVersion = 1;
private final Context ProvidedContext;

public DatabaseProvider(Context context) {
    super(context, DatabaseName, null, DatabaseVersion);
    this.ProvidedContext= context;
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    boolean databaseCopied = preferences.getBoolean("DatabaseCopied", false);
    if (databaseCopied) {
        //Do Nothing
    } else {
        CopyDatabase();
        SharedPreferences.Editor editor = preferences.edit();
        editor.putBoolean("DatabaseCopied", true);
        editor.commit();
    }
}

private String DatabasePath() {
    return "/data/data/" + ProvidedContext.getPackageName() + "/databases/";
}

private void CopyDatabase() {
    try {
        CopyDatabaseInternal();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private File ExtractAssetsZip(String zipFileName) {
    InputStream inputStream;
    ZipInputStream zipInputStream;
    File tempFolder;
    do {
        tempFolder = null;
        tempFolder = new File(ProvidedContext.getCacheDir() + "/extracted-" + System.currentTimeMillis() + "/");
    } while (tempFolder.exists());

    tempFolder.mkdirs();

    try {
        String filename;
        inputStream = ProvidedContext.getAssets().open(zipFileName);
        zipInputStream = new ZipInputStream(new BufferedInputStream(inputStream));
        ZipEntry zipEntry;
        byte[] buffer = new byte[1024];
        int count;

        while ((zipEntry = zipInputStream.getNextEntry()) != null) {
            filename = zipEntry.getName();
            if (zipEntry.isDirectory()) {
                File fmd = new File(tempFolder.getAbsolutePath() + "/" + filename);
                fmd.mkdirs();
                continue;
            }

            FileOutputStream fileOutputStream = new FileOutputStream(tempFolder.getAbsolutePath() + "/" + filename);
            while ((count = zipInputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, count);
            }

            fileOutputStream.close();
            zipInputStream.closeEntry();
        }

        zipInputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }

    return tempFolder;
}

private void CopyDatabaseInternal() throws IOException {

    File extractedPath = ExtractAssetsZip(DatabaseName + ".zip");
    String databaseFile = "";
    for (File innerFile : extractedPath.listFiles()) {
        databaseFile = innerFile.getAbsolutePath();
        break;
    }
    if (databaseFile == null || databaseFile.length() ==0 )
        throw new RuntimeException("databaseFile is empty");

    InputStream inputStream = new FileInputStream(databaseFile);

    String outFileName = DatabasePath() + DatabaseName;

    File destinationPath = new File(DatabasePath());
    if (!destinationPath.exists())
        destinationPath.mkdirs();

    File destinationFile = new File(outFileName);
    if (!destinationFile.exists())
        destinationFile.createNewFile();

    OutputStream myOutput = new FileOutputStream(outFileName);

    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    myOutput.flush();
    myOutput.close();
    inputStream.close();
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource) {
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource, int fromVersion, int toVersion) {

}

}
코드는 자산의 zip 파일에서 데이터베이스 파일을 추출합니다.

공유 이 답변을 개선 따르다
생성 12 jul.

호마윤 베자 디안
7085은색 배지 5 개2121 개의 브론즈 배지
의견을 추가하다

0

ROOM 을 사용 하는 경우 공식 문서에 이미 https://developer.android.com/training/data-storage/room/prepopulate 매우 간단한 경로가 있습니다. 자산 파일에서 데이터베이스를 다시 채우는 방법은 다음과 같습니다.

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromAsset("database/myapp.db")
.build()
또는 파일에서 :

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromFile(File("mypath"))
.build()
Room을 사용하지 않는다면 강력히 추천합니다 😁