Статьи

Сохранение изображения в базе данных SQLite в вашем приложении Android

Когда вы начнете кэшировать данные в локальной базе данных из вашего приложения Android, рано или поздно вам также потребуется сохранить изображения в этой базе данных. Например, если вы храните отчеты о наблюдениях, которые пользователи проводят в поле, которое будет загружено в основную систему позже, может быть удобно добавить изображение, чтобы лучше описать проблему.

Первая идея, которая приходит на ум для хранения этих изображений, — это сохранение их непосредственно в базе данных в виде больших двоичных объектов (больших двоичных объектов). Это может работать, но это не самый эффективный способ сделать это, поскольку SQLite предназначен для хранения значений, а не больших двоичных значений. Кроме того, локальная база данных может стать довольно большой, особенно если вам нужно сохранить полноразмерные высококачественные изображения. Вы можете проверить эталонный тест на официальном сайте SQLite по адресу https://www.sqlite.org/intern-v-extern-blob.html, если хотите получить лучшее представление о производительности.

В этом случае вы действительно хотите сохранить только путь к изображению в вашей базе данных и сохранить изображение во внутреннем хранилище вашего приложения. Когда вам нужно использовать изображение, вы можете просто использовать путь для извлечения изображения из файловой системы. Я рекомендую вам сохранить изображения во внутреннем хранилище, так как они доступны только из вашего приложения и доступны в любое время; фактически, сама база данных SQLite также хранится во внутренней памяти.

Вот пример того, как добавить изображение в существующий отчет, сохранить его во внутреннем хранилище и сохранить путь в базе данных. Чтобы узнать больше о том, как создать базу данных и сохранить в ней данные, вы можете прочитать мою статью о сохранении в базе данных SQLite .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class ApplicationDatabaseHelper extends SQLiteOpenHelper {
/**
  * Updates the current picture for the report.
  *
  * @param reportId the identifier of the report for which to save the picture
  * @param picture the picture to save to the internal storage and save path in the database.
  */
public void updateReportPicture(long reportId, Bitmap picture) {
   // Saves the new picture to the internal storage with the unique identifier of the report as
   // the name. That way, there will never be two report pictures with the same name.
   String picturePath = "";
   File internalStorage = mContext.getDir("ReportPictures", Context.MODE_PRIVATE);
   File reportFilePath = new File(internalStorage, reportId + ".png");
   String picturePath = reportFilePath.toString();
 
   FileOutputStream fos = null;
   try {
      fos = new FileOutputStream(reportFilePath);
      picture.compress(Bitmap.CompressFormat.PNG, 100 /*quality*/, fos);
      fos.close();
      }
   catch (Exception ex) {
      Log.i("DATABASE", "Problem updating picture", ex);
      picturePath = "";
      }
 
   // Updates the database entry for the report to point to the picture
   SQLiteDatabase db = getWritableDatabase();
 
   ContentValues newPictureValue = new ContentValues();
   newPictureValue.put(ReportContract.ReportEntry.COLUMN_PICTURE_TITLE,
                       picturePath);
 
   db.update(ReportContract.TABLE_NAME,
             newPictureValue,
             ReportContract.ReportEntry._ID + "=?",
             new String[]{String.valueOf(reportId)});
   }
}

Если вы сохраняете изображение в базе данных, вам также нужен способ заставить это изображение отображаться в вашем приложении. Вот как получить изображение, которое было только что сохранено, чтобы отобразить его снова:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class ApplicationDatabaseHelper extends SQLiteOpenHelper {
/**
  * Gets the picture for the specified report in the database.
  *
  * @param reportId the identifier of the report for which to get the picture.
  *
  * @return the picture for the report, or null if no picture was found.
  */
public Bitmap getReportPicture(long reportId) {
   String picturePath = getReportPicturePath(reportId);
   if (picturePath == null || picturePath.length() == 0)
      return (null);
 
   Bitmap reportPicture = BitmapFactory.decodeFile(picturePath);
 
   return (reportPicture);
   }
 
/**
  * Gets the path of the picture for the specified report in the database.
  *
  * @param reportId the identifier of the report for which to get the picture.
  *  
  * @return the picture for the report, or null if no picture was found.
  */
private String getReportPicturePath(long reportId) {
   // Gets the database in the current database helper in read-only mode
   SQLiteDatabase db = getReadableDatabase();
 
   // After the query, the cursor points to the first database row
   // returned by the request
   Cursor reportCursor = db.query(ReportContract.TABLE_NAME,
                                  null,
                                  ReportContract.ReportEntry._ID + "=?",
                                  new String[]{String.valueOf(reportId)},
                                  null,
                                  null,
                                  null);
   reportCursor.moveToNext();
     
   // Get the path of the picture from the database row pointed by
   // the cursor using the getColumnIndex method of the cursor.
   String picturePath = reportCursor.getString(reportCursor.
                             getColumnIndex(ReportContract.ReportEntry.COLUMN_PICTURE_TITLE));
 
   return (picturePath);
   }
}

Наконец, вам нужно обязательно удалить картинку из внутреннего хранилища, если вы удалите связанную запись из базы данных. Если вы сохраняете изображения, внутреннее хранилище, используемое вашим приложением, со временем будет увеличиваться, и ваши пользователи не смогут удалить эти изображения, поскольку внутреннее хранилище скрыто от них.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ApplicationDatabaseHelper extends SQLiteOpenHelper {
/**
  * Deletes the specified report from the database, removing also the associated picture from the
  * internal storage if any.
  *
  * @param reportId the report to remove.
  */
public void deleteReport(long reportId) {
   // Remove picture for report from internal storage
   String picturePath = getReportPicturePath(reportId); // See above
   if (picturePath != null && picturePath.length() != 0) {
      File reportFilePath = new File(picturePath);
      reportFilePath.delete();
   }
 
   // Remove the report from the database
   SQLiteDatabase db = getWritableDatabase();
 
   db.delete(ReportContract.TABLE_NAME,
             ReportContract.ReportEntry._ID + "=?",
             new String[]{String.valueOf(reportId)});
   }
}