First Thanks @masmic. I use it to make some search in github repos and made my own way. Note that I use kotlin, coroutines and crashlitics you can get rid of all that with Java, posting a thread to a Handler and send data to your custom sever with okhttp.
My code can Save bitmap to app folder i.e. local store. and read load it is:.
package xxxx.data import android.content.Context import android.content.ContextWrapper import android.graphics.Bitmap import android.graphics.BitmapFactory import android.util.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.ktx.Firebase import java.io.ByteArrayOutputStream import java.io.File import java.io.FileInputStream import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.IOException import java.util.Date interface BitmapDAO { suspend fun insertBitmapAndGetRelativePath(bitmapEntity: PhotoEntity): String? suspend fun getBitmapFromPath(bitmapEntity: PhotoEntity): Bitmap? suspend fun deleteFile(bitmapEntity: PhotoEntity) : Boolean suspend fun updateBitmap(bitmapEntity: PhotoEntity): Boolean } class BitmapDAOImpl(private val mContext: Context): BitmapDAO { companion object{ //private const val MIME_TYPE_IMAGE:String = "image/*" private const val FILE_EXTENSION:String = ".jpeg" private const val FOLDER:String = "images" } private fun convertFromBitMapToByteArray(bitmap: Bitmap) : ByteArray { val byteArrayOutputStream = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.JPEG,100,byteArrayOutputStream) return byteArrayOutputStream.toByteArray() } override suspend fun insertBitmapAndGetRelativePath(bitmapEntity: PhotoEntity): String? { val bitmap: Bitmap = bitmapEntity.bitmap.let { bitmap -> return@let bitmap }?: return null val productName: String = bitmapEntity.productName.let { productName -> return@let productName }?: return null // Get the context wrapper val wrapper = ContextWrapper(mContext) val fileName: String = productName + Date().time.toString() + FILE_EXTENSION try { /** * Caution: On devices that run Android 7.0 (API level 24) or higher, * unless you pass the Context.MODE_PRIVATE file mode * into openFileOutput(), a SecurityException occurs. */ return withContext(Dispatchers.IO) { // Initialize a new file instance to save bitmap object var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE) if (!fileDir.exists()) { fileDir.mkdir() } fileDir = File(fileDir, fileName) //with mContext.openFileOutput It gets: EISDIR (Is a directory) FileOutputStream(fileDir).use { it.write(convertFromBitMapToByteArray(bitmap)) } //Uri.parse(file.absolutePath) return@withContext fileName } } catch (ex: FileNotFoundException) { //REPORT Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl") Firebase.crashlytics.setCustomKey("Method", "insertBitmapAndGetUri") Firebase.crashlytics.setCustomKey("UseCase", "saveImage") Firebase.crashlytics.recordException(ex) Log.e("BitmapDAOImpl FileNotFoundException", ex.message ?: "") Log.e("BitmapDAOImpl FileNotFoundException", ex.stackTrace.toString()) } catch (ex: IOException) { //REPORT Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl") Firebase.crashlytics.setCustomKey("Method", "insertBitmapAndGetUri") Firebase.crashlytics.setCustomKey("UseCase", "saveImage") Firebase.crashlytics.recordException(ex) Log.e("BitmapDAOImpl IOException", ex.message ?: "") Log.e("BitmapDAOImpl IOException", ex.stackTrace.toString()) } //only for Exception case return null } override suspend fun getBitmapFromPath(bitmapEntity: PhotoEntity): Bitmap? { try { val wrapper = ContextWrapper(mContext) return withContext(Dispatchers.IO) { var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE) if (!fileDir.exists()) { fileDir.mkdir() } fileDir = File(fileDir, bitmapEntity.fileName) var payload : Bitmap? = null if (fileDir.exists()){ FileInputStream(fileDir).use { fileInputStream -> /** * Loading image */ payload = BitmapFactory.decodeStream(fileInputStream) } } return@withContext payload } } catch (ex: FileNotFoundException) { //REPORT Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl") Firebase.crashlytics.setCustomKey("Method", "getBitmapFromUri") Firebase.crashlytics.setCustomKey("UseCase", "readImage") Firebase.crashlytics.recordException(ex) Log.e("BitmapDAOImpl", ex.message ?: "") Log.e("BitmapDAOImpl", ex.stackTrace.toString()) } catch (out: OutOfMemoryError) { //REPORT Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl") Firebase.crashlytics.setCustomKey("Method", "getBitmapFromUri") Firebase.crashlytics.setCustomKey("UseCase", "readImage") Firebase.crashlytics.recordException(out) Log.e("BitmapDAOImpl", out.message ?: "") Log.e("BitmapDAOImpl", out.stackTrace.toString()) } // If an error has occurred or the album ID is null, then return a default artwork image //return BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_launcher_foreground) //only for Exception case return null } override suspend fun deleteFile(bitmapEntity: PhotoEntity) : Boolean { val wrapper = ContextWrapper(mContext) try { return withContext(Dispatchers.IO) { var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE) if (!fileDir.exists()) { fileDir.mkdir() } fileDir = File(fileDir, bitmapEntity.fileName) if(fileDir.exists()){ return@withContext fileDir.delete() } else { return@withContext false } } } catch (ex: FileNotFoundException) { //REPORT Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl") Firebase.crashlytics.setCustomKey("Method", "deleteFile") Firebase.crashlytics.setCustomKey("UseCase", "deleteImage") Firebase.crashlytics.recordException(ex) Log.e("BitmapDAOImpl", ex.message ?: "") Log.e("BitmapDAOImpl", ex.stackTrace.toString()) } //only for Exception case return false } override suspend fun updateBitmap(bitmapEntity: PhotoEntity):Boolean { val newImage: Bitmap = bitmapEntity.bitmap.let { newImage -> return@let newImage }?: return false val wrapper = ContextWrapper(mContext) try { return withContext(Dispatchers.IO) { var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE) if (!fileDir.exists()) { fileDir.mkdir() } fileDir = File(fileDir, bitmapEntity.fileName) //if(fileDir.exists()) ?? for both case is the same FileOutputStream(fileDir).use { it.write(convertFromBitMapToByteArray(newImage)) } return@withContext true } } catch (ex: Exception) { //REPORT Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl") Firebase.crashlytics.setCustomKey("Method", "updateBitmapAndGetUri") Firebase.crashlytics.setCustomKey("UseCase", "updateImage") Firebase.crashlytics.recordException(ex) Log.e("BitmapDAOImpl", ex.message ?: "") Log.e("BitmapDAOImpl", ex.stackTrace.toString()) } return false } } //End of class
Thanks. And have a nice day.