検証環境
この記事の内容は、以下の環境で検証しました。
- Java:open jdk 1.8.0_152
- Kotlin 1.2.0
- Android Studio 3.0.2
- CompileSdkVersion:26
- MinSdkVersion:21
- TargetSdkVersion:26
- BuildToolsVersion:26.0.2
- gradle:4.0.0
目標
本記事では、以下の2点を目標としています。
- アプリ内で画像をDCIMに保存する
- 保存した画像をギャラリーに表示させる
アプリの動き
この記事で作成するアプリは、下記の仕様になっています。
ファイル構成
この記事で作成するアプリは下記のファイルで構成しています。
ファイル名 | 説明 |
---|---|
AndroidManifest.xml | マニフェストファイル |
layout/activity_main.xml | 画面のレイアウト |
jp.co.casareal.filetodcim.MainActivity | ファイルの保存処理が記載されているActivity |
drawable/pic.png | サンプル画像 |
画像をDCIMに保存する
AndroidManifest.xml
コード
DCIMは外部ストレージの扱いになるため、外部ストレージへのパーミッションを追記します。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.co.casareal.filetodcim">
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
コード
保存するためのボタンと、保存する画像のサンプルを表示するImageViewを配置しています。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下記の画像をDCIMに保存" />
<ImageView
android:src="@drawable/pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
jp.co.casareal.filetodcim.MainActivity
コード
本記事のコードでは、下記の処理を実装しています。
- 外部ストレージへの書き込み権限を取得するために、ダイアログを表示しています。
- 外部ストレージのパスを取得し、Fileクラスを生成します。
- BitmapFactoryを利用してpic.jpegを読み込み、DCIMに保存します。
- ギャラリーからもアクセス出来るように、画像データとしてAndroidに登録します。
コードの全体像
package jp.co.casareal.filetodcim
import android.Manifest
import android.content.ContentValues
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.io.File
import java.io.FileOutputStream
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
super.onResume()
btn_save.setOnClickListener {
if (ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1)
} else {
saveFile(createFile())
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
// 絶対に許可される前提で記述
saveFile(createFile())
}
private fun createFile(): File {
val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
return File(dir, "pic.jpeg")
}
private fun saveFile(f: File) {
val bit = BitmapFactory.decodeResource(resources, R.drawable.pic)
val ops = FileOutputStream(f)
bit.compress(Bitmap.CompressFormat.PNG, 100, ops)
ops.close()
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put("_data", f.absolutePath)
}
contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
}
}
外部ストレージへの書き込み権限を取得するためのダイアログ表示
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1)
外部ストレージのパスを取得し、Fileクラスの生成
private fun createFile(): File {
val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
return File(dir, "pic.jpeg")
}
BitmapFactoryを利用してpic.jpegを読み込み、DCIMに保存
val bit = BitmapFactory.decodeResource(resources, R.drawable.pic)
val ops = FileOutputStream(f)
bit.compress(Bitmap.CompressFormat.PNG, 100, ops)
ops.close()
ギャラリーからもアクセス出来るように、画像データとしてAndroidに登録
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put("_data", f.absolutePath)
}
contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
もう一つ方法があります。ブロードキャストでOSに今一度スキャンをさせるという方法です。
ただし、アプリ内のフォルダに画像を保存した場合は、対象にならないので保存する場所に注意が必要です。
val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
val contentUri = Uri.fromFile(f)
mediaScanIntent.data = contentUri
this.sendBroadcast(mediaScanIntent)