6

私のAndroidアプリケーションには、大規模なデータベース(約45 MB)を使用したいと思います。

1つの解決策は、(分割された)データベースをアセットフォルダーに含め、最初の起動時にデータベースディレクトリにコピーすることです。

ただし、これによりディスク領域が2回消費されます。1回はファイルを削除できないアセットフォルダで、もう1回はファイルのコピー先のデータベースディレクトリで使用されます。

ですから、最初の起動時にインターネット(ウェブサーバー)からデータベースをダウンロードしたいと思います。どうすればこれを行うことができますか?完全なSQLiteファイルをダウンロードしてデータベースディレクトリに保存できますか?または、データベースにデータを入力するために使用されるJSONデータファイルを使用する必要がありますか?

4

3 に答える 3

12

1つの解決策は、(分割された)データベースをアセットフォルダーに含め、最初の起動時にデータベースディレクトリにコピーすることです。

分割する必要はなく、ZIPするだけです。例についてはを参照SQLiteAssetHelperしてください。

どうすればこれを行うことができますか?

を使用しHttpUrlConnectionます。または、を使用しますHttpClient

完全なSQLiteファイルをダウンロードしてデータベースディレクトリに保存できますか?

はい。を使用getDatabasePath()して、使用する正しいローカルパスを取得します。

または、データベースにデータを入力するために使用されるJSONデータファイルを使用する必要がありますか?

可能ですが、45MBの場合、それは非常に遅くなります。

于 2012-04-20T23:43:58.293 に答える
8

最終的にどのような解決策が得られたかを尋ねられたので、これが私が使用したコードです(大まかに)。それはもう完全ではないかもしれません、そしてそれはエレガントでもきれいでもありません。しかし、多分それはあなたの助けになるかもしれません。

MyActivity.java

public class MyActivity extends Activity {

    private static final String SD_CARD_FOLDER = "MyApp";
    private static final String DB_DOWNLOAD_PATH = "http://www.example.org/downloads/dictionary.sqlite";
    private Database mDB = null;
    private DatabaseDownloadTask mDatabaseDownloadTask = null;
    private DatabaseOpenTask mDatabaseOpenTask = null;

    private class DatabaseDownloadTask extends AsyncTask<Context, Integer, Boolean> {

        @Override
        protected void onPreExecute() {
            mProgressDialog = new ProgressDialog(MyActivity.this);
            mProgressDialog.setTitle(getString(R.string.please_wait));
            mProgressDialog.setMessage(getString(R.string.downloading_database));
            mProgressDialog.setIndeterminate(false);
            mProgressDialog.setMax(100);
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            mProgressDialog.setCancelable(false);
            mProgressDialog.show();
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }

        @Override
        protected Boolean doInBackground(Context... params) {
            try {
                File dbDownloadPath = new File(Database.getDatabaseFolder());
                if (!dbDownloadPath.exists()) {
                    dbDownloadPath.mkdirs();
                }
                HttpParams httpParameters = new BasicHttpParams();
                HttpConnectionParams.setConnectionTimeout(httpParameters, 5000);
                HttpConnectionParams.setSoTimeout(httpParameters, 5000);
                DefaultHttpClient client = new DefaultHttpClient(httpParameters);
                HttpGet httpGet = new HttpGet(DB_DOWNLOAD_PATH);
                InputStream content = null;
                try {
                    HttpResponse execute = client.execute(httpGet);
                    if (execute.getStatusLine().getStatusCode() != 200) { return null; }
                    content = execute.getEntity().getContent();
                    long downloadSize = execute.getEntity().getContentLength();
                    FileOutputStream fos = new FileOutputStream(Database.getDatabaseFolder()+Database.DATABASE_NAME+".sqlite");
                    byte[] buffer = new byte[256];
                    int read;
                    long downloadedAlready = 0;
                    while ((read = content.read(buffer)) != -1) {
                        fos.write(buffer, 0, read);
                        downloadedAlready += read;
                        publishProgress((int) (downloadedAlready*100/downloadSize));
                    }
                    fos.flush();
                    fos.close();
                    content.close();
                    return true;
                }
                catch (Exception e) {
                    if (content != null) {
                        try {
                            content.close();
                        }
                        catch (IOException e1) {}
                    }
                    return false;
                }
            }
            catch (Exception e) {
                return false;
            }
        }

        protected void onProgressUpdate(Integer... values) {
            if (mProgressDialog != null) {
                if (mProgressDialog.isShowing()) {
                    mProgressDialog.setProgress(values[0]);
                }
            }
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (mProgressDialog != null) {
                mProgressDialog.dismiss();
                mProgressDialog = null;
            }
            if (result.equals(Boolean.TRUE)) {
                Toast.makeText(MyActivity.this, getString(R.string.database_download_success), Toast.LENGTH_LONG).show();
                mDatabaseOpenTask = new DatabaseOpenTask();
                mDatabaseOpenTask.execute(new Context[] { MyActivity.this });
            }
            else {
                Toast.makeText(getApplicationContext(), getString(R.string.database_download_fail), Toast.LENGTH_LONG).show();
                finish();
            }
        }

    }

    private class DatabaseOpenTask extends AsyncTask<Context, Void, Database> {

        @Override
        protected Database doInBackground(Context ... ctx) {
            try {
                String externalBaseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
                // DELETE OLD DATABASE ANFANG
                File oldFolder = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+SD_CARD_FOLDER);
                File oldFile = new File(oldFolder, "dictionary.sqlite");
                if (oldFile.exists()) {
                    oldFile.delete();
                }
                if (oldFolder.exists()) {
                    oldFolder.delete();
                }
                // DELETE OLD DATABASE ENDE
                File newDB = new File(Database.getDatabaseFolder()+"dictionary.sqlite");
                if (newDB.exists()) {
                    return new Database(ctx[0]);
                }
                else {
                    return null;
                }
            }
            catch (Exception e) {
                return null;
            }
        }

        @Override
        protected void onPreExecute() {
            mProgressDialog = ProgressDialog.show(MainActivity.this, getString(R.string.please_wait), "Loading the database! This may take some time ...", true);
        }

        @Override
        protected void onPostExecute(Database newDB) {
            if (mProgressDialog != null) {
                mProgressDialog.dismiss();
                mProgressDialog = null;
            }
            if (newDB == null) {
                mDB = null;
                AlertDialog.Builder downloadDatabase = new AlertDialog.Builder(MyActivity.this);
                downloadDatabase.setTitle(getString(R.string.downloadDatabase));
                downloadDatabase.setCancelable(false);
                downloadDatabase.setMessage(getString(R.string.wantToDownloadDatabaseNow));
                downloadDatabase.setPositiveButton(getString(R.string.download), new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        mDatabaseDownloadTask = new DatabaseDownloadTask();
                        mDatabaseDownloadTask.execute();
                    }
                });
                downloadDatabase.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                    }
                });
                downloadDatabase.show();
            }
            else {
                mDB = newDB;
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mDatabaseDownloadTask != null) {
            if (mDatabaseDownloadTask.getStatus() != AsyncTask.Status.FINISHED) {
                mDatabaseDownloadTask.cancel(true);
            }
        }
        if (mDatabaseOpenTask != null) {
            if (mDatabaseOpenTask.getStatus() != AsyncTask.Status.FINISHED) {
                mDatabaseOpenTask.cancel(true);
            }
        }
        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
            mProgressDialog = null;
        }
        if (mDB != null) {
            mDB.close();
            mDB = null;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Toast.makeText(getApplicationContext(), getString(R.string.sd_card_not_found), Toast.LENGTH_LONG).show();
            finish();
        }
        mDatabaseOpenTask = new DatabaseOpenTask();
        mDatabaseOpenTask.execute(new Context[] { this });
    }

}

Database.java

パブリッククラスデータベースはSQLiteOpenHelperを拡張します{

private static final String DATABASE_NAME = "dictionary";
private String DATABASE_PATH = null;
private static final int DATABASE_VERSION = 1;
private static final String PACKAGE_NAME = "com.my.package";
private SQLiteDatabase db;

public Database(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    DATABASE_PATH = getDatabaseFolder()+DATABASE_NAME+".sqlite";
    db = getWritableDatabase();
}

public static String getDatabaseFolder() {
    return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Android/data/"+PACKAGE_NAME+"/databases/";
}

@Override
public synchronized SQLiteDatabase getWritableDatabase() {
    try {
        if (db != null) {
            if (db.isOpen()) {
                return db;
            }
        }
        return SQLiteDatabase.openDatabase(DATABASE_PATH, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
    }
    catch (Exception e) {
        return null;
    }
}

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

@Override
public void onCreate(SQLiteDatabase db) { }

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }

}

于 2014-03-06T21:02:29.760 に答える
3

データベースがそれほど大きい場合は、JSONアプローチの方が適していると思います。

100%確実ではありませんが、アプリケーションの更新をリリースすると、デバイスがアプリケーション全体をダウンロードすると思います。45 MBのファイルをアプリケーションにバンドルしている場合、更新をプッシュするたびに、ユーザーは45MBのファイルのダウンロードに行き詰まります。良い考えではありません。

できることは、アプリケーションにデータのない適切に構造化されたデータベースを含めることです。ユーザーがアプリケーションを開くと、Webサーバーに接続し、JSONデータを取得してデータベースにデータを入力できます。このようにして、ユーザーがアプリケーションを更新するときに、新しい大きなファイルのダウンロードにとらわれることはありません。更新によって既存のデータベースが消去されることはありません。

ユーザーがすべてを手に入れるまで、JSONを介してデータベースの一部を取得することもできます。このように、モンスタークエリを実行していて、インターネットへの接続が失われた場合でも、それほど悪いことは起こりません。

于 2012-04-20T23:52:16.710 に答える