Saving and Reading Bitmaps/Images from Internal memory in Android - android

What I want to do, is to save an image to the internal memory of the phone (Not The SD Card).
How can I do it?
I have got the image directly from the camera to the image view in my app its all working fine.
Now what I want is to save this image from Image View to the Internal memory of my android device and also access it when required.
Can anyone please guide me how to do this?
I am a little new to android so please, I would appreciate if I can have a detailed procedure.

Use the below code to save the image to internal directory.
private String saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,"profile.jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return directory.getAbsolutePath();
}
Explanation :
1.The Directory will be created with the given name. Javadocs is for to tell where exactly it will create the directory.
2.You will have to give the image name by which you want to save it.
To Read the file from internal memory. Use below code
private void loadImageFromStorage(String path)
{
try {
File f=new File(path, "profile.jpg");
Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
ImageView img=(ImageView)findViewById(R.id.imgPicker);
img.setImageBitmap(b);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}

/**
* Created by Ilya Gazman on 3/6/2016.
*/
public class ImageSaver {
private String directoryName = "images";
private String fileName = "image.png";
private Context context;
private boolean external;
public ImageSaver(Context context) {
this.context = context;
}
public ImageSaver setFileName(String fileName) {
this.fileName = fileName;
return this;
}
public ImageSaver setExternal(boolean external) {
this.external = external;
return this;
}
public ImageSaver setDirectoryName(String directoryName) {
this.directoryName = directoryName;
return this;
}
public void save(Bitmap bitmapImage) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(createFile());
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
#NonNull
private File createFile() {
File directory;
if(external){
directory = getAlbumStorageDir(directoryName);
}
else {
directory = context.getDir(directoryName, Context.MODE_PRIVATE);
}
if(!directory.exists() && !directory.mkdirs()){
Log.e("ImageSaver","Error creating directory " + directory);
}
return new File(directory, fileName);
}
private File getAlbumStorageDir(String albumName) {
return new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
}
public static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}
public static boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
}
public Bitmap load() {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(createFile());
return BitmapFactory.decodeStream(inputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
Usage
To save:
new ImageSaver(context).
setFileName("myImage.png").
setDirectoryName("images").
save(bitmap);
To load:
Bitmap bitmap = new ImageSaver(context).
setFileName("myImage.png").
setDirectoryName("images").
load();
Edit:
Added ImageSaver.setExternal(boolean) to support saving to external storage based on googles example.

Came across this question today and this is how I do it.
Just call this function with the required parameters
public void saveImage(Context context, Bitmap bitmap, String name, String extension){
name = name + "." + extension;
FileOutputStream fileOutputStream;
try {
fileOutputStream = context.openFileOutput(name, Context.MODE_PRIVATE);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Similarly, for reading the same, use this
public Bitmap loadImageBitmap(Context context,String name,String extension){
name = name + "." + extension
FileInputStream fileInputStream
Bitmap bitmap = null;
try{
fileInputStream = context.openFileInput(name);
bitmap = BitmapFactory.decodeStream(fileInputStream);
fileInputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
return bitmap;
}

For Kotlin users, I created a ImageStorageManager class which will handle save, get and delete actions for images easily:
class ImageStorageManager {
companion object {
fun saveToInternalStorage(context: Context, bitmapImage: Bitmap, imageFileName: String): String {
context.openFileOutput(imageFileName, Context.MODE_PRIVATE).use { fos ->
bitmapImage.compress(Bitmap.CompressFormat.PNG, 25, fos)
}
return context.filesDir.absolutePath
}
fun getImageFromInternalStorage(context: Context, imageFileName: String): Bitmap? {
val directory = context.filesDir
val file = File(directory, imageFileName)
return BitmapFactory.decodeStream(FileInputStream(file))
}
fun deleteImageFromInternalStorage(context: Context, imageFileName: String): Boolean {
val dir = context.filesDir
val file = File(dir, imageFileName)
return file.delete()
}
}
}
Read more here

This code will support up Upto Android 11+.
Declare a permission result on Fragment / Activity
I am using a fragment
private val askPermissions =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
val isGranted = permissions.entries.all {
it.value == true
}
if (isGranted) {
viewModel.saveImageToGallery(requireContext().contentResolver,
getString(R.string.my_deshi_qr_code),
bitmap)
} else {
askForWritePermission()
}
}
Trigger event
bindingView.downloadQrButton.setOnClickListener {
requestPermission()
}
private fun requestPermission() {
val minSDK = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
val isWritePermissionGranted = (ContextCompat.checkSelfPermission(requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) || minSDK
if (!isWritePermissionGranted) {
askForWritePermission()
} else {
viewModel.saveImageToGallery(requireContext().contentResolver,
getString(R.string.my_deshi_qr_code),
bitmap)
}
}
private fun askForWritePermission() {
askPermissions.launch(listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE).toTypedArray())
}
Viewmodel
fun saveImageToGallery(contentResolver: ContentResolver, imageName: String, bitmap: Bitmap?) {
val imageUri: Uri?
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "$imageName.jpg")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
bitmap?.let {
put(MediaStore.Images.Media.WIDTH, bitmap.width)
put(MediaStore.Images.Media.HEIGHT, bitmap.height)
}
}
imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,
Environment.DIRECTORY_PICTURES + File.separator.toString() + "YourFolderName")
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
try {
val uri = contentResolver.insert(imageUri, contentValues)
val fos = uri?.let { contentResolver.openOutputStream(it) }
bitmap?.compress(Bitmap.CompressFormat.JPEG, 100, fos)
Objects.requireNonNull(fos)
_showMessage.postValue(Event("Image Saved"))
} catch (e: Exception) {
_showMessage.postValue(Event("Image Not Saved \n$e"))
}
}

// mutiple image retrieve
File folPath = new File(getIntent().getStringExtra("folder_path"));
File[] imagep = folPath.listFiles();
for (int i = 0; i < imagep.length ; i++) {
imageModelList.add(new ImageModel(imagep[i].getAbsolutePath(), Uri.parse(imagep[i].getAbsolutePath())));
}
imagesAdapter.notifyDataSetChanged();

if you want to follow Android 10 practices to write in storage, check here
and if you only want the images to be app specific, here
for example if you want to store an image just to be used by your app:
viewModelScope.launch(Dispatchers.IO) {
getApplication<Application>().openFileOutput(filename, Context.MODE_PRIVATE).use {
bitmap.compress(Bitmap.CompressFormat.PNG, 50, it)
}
}
getApplication is a method to give you context for ViewModel and it's part of AndroidViewModel
later if you want to read it:
viewModelScope.launch(Dispatchers.IO) {
val savedBitmap = BitmapFactory.decodeStream(
getApplication<App>().openFileInput(filename).readBytes().inputStream()
)
}

Make sure to use WEBP as your media format to save more space with same quality:
fun saveImage(context: Context, bitmap: Bitmap, name: String): String {
context.openFileOutput(name, Context.MODE_PRIVATE).use { fos ->
bitmap.compress(Bitmap.CompressFormat.WEBP, 25, fos)
}
return context.filesDir.absolutePath
}

Related

create an tempDir and save it into an IFile with the external_drive_lib

Currently i am Getting from the IDrive an folder which has a file and i am copying this file into a tempfile which i am reading with the Streamreader, but is there a way to create this IFIle or i chnage the tempfile and save it into the IFile?
public IFolder TryToGetFolder(IDrive drive, string folderPath)
{
if (drive.is_connected())
{
try
{
return drive.try_parse_folder(folderPath);
}
catch
{
return null;
}
}
else
return null;
}
//Tries to get a file in a folder or returns null
public IFile TryToGetFile(IFolder folder, string filename)
{
return folder.files.Where(f => f.name == filename).FirstOrDefault();
}
//Tries to read the text of a file or returns null
public string TryToGetFileText(IFile file)
{
//Uses the tempDir to copy the file to it
string tempDir = _tempDir + "temp-" + DateTime.Now.Ticks;
Directory.CreateDirectory(tempDir);
file.copy_sync(tempDir);
//Read file from tempDir
StreamReader reader = new StreamReader(tempDir + "\\" + file.name);
return reader.ReadToEnd();
}
//Tries to delete a file
public void TryToDeleteFile(IFile file)
{
if(file != null)
{
if (file.exists)
file.delete_sync();
}
}
I tried this but this is using a Process Class, which i havent seen before.
//Tries to Send a file from the WPF to the Android Device
public bool SendFileToAndroid(AndroidDevice device, string filePath, CWCProduct cWCProduct)
{
if (!device.Drive.is_connected())
return false;
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "adb",
Arguments = $"push {filePath} {cWCProduct}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
process.WaitForExit();
return true;
}
catch
{
return false;
}
}

Issue in showing PDF file print view using Android print framework

I have followed this sample code to show a print view by passing existing PDF from my file system. But I noticed that it is not able to show all the PDFs in print view.
PdfDocumentAdapter.java
public class PdfDocumentAdapter extends PrintDocumentAdapter {
Context context = null;
String pathName = "";
public PdfDocumentAdapter(Context ctxt, String pathName) {
context = ctxt;
this.pathName = pathName;
}
#Override
public void onLayout(PrintAttributes printAttributes, PrintAttributes printAttributes1, CancellationSignal cancellationSignal, LayoutResultCallback layoutResultCallback, Bundle bundle) {
if (cancellationSignal.isCanceled()) {
layoutResultCallback.onLayoutCancelled();
}
else {
PrintDocumentInfo.Builder builder=
new PrintDocumentInfo.Builder(" file name");
builder.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
.build();
layoutResultCallback.onLayoutFinished(builder.build(),
!printAttributes1.equals(printAttributes));
}
}
#Override
public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor parcelFileDescriptor, CancellationSignal cancellationSignal, WriteResultCallback writeResultCallback) {
InputStream in=null;
OutputStream out=null;
try {
File file = new File(pathName);
in = new FileInputStream(file);
out=new FileOutputStream(parcelFileDescriptor.getFileDescriptor());
byte[] buf=new byte[16384];
int size;
while ((size=in.read(buf)) >= 0
&& !cancellationSignal.isCanceled()) {
out.write(buf, 0, size);
}
if (cancellationSignal.isCanceled()) {
writeResultCallback.onWriteCancelled();
}
else {
writeResultCallback.onWriteFinished(new PageRange[] { PageRange.ALL_PAGES });
}
}
catch (Exception e) {
writeResultCallback.onWriteFailed(e.getMessage());
Logger.logError( e);
}
finally {
try {
in.close();
out.close();
}
catch (IOException e) {
Logger.logError( e);
}
}
}
}
calling this by PrintManager
PrintManager printManager=(PrintManager) SurefoxBrowserScreen.getActivityContext().getSystemService(Context.PRINT_SERVICE);
try
{
PrintDocumentAdapter printAdapter = new PdfDocumentAdapter(Settings.sharedPref.context,filePath );
}
printManager.print("Document", printAdapter,new PrintAttributes.Builder().build());
}
catch (Exception e)
{
Logger.logError(e);
}
This code is not able to show this PDF, it loads empty pages without any content in it.
https://www.scala-lang.org/old/sites/default/files/linuxsoft_archives/docu/files/ScalaByExample.pdf
but it is working for this PDF:
https://www.tutorialspoint.com/scala/scala_tutorial.pdf .
I have checked with different PDFs. Some of them are working and some are not.
How can I fix this problem?

Downloading multiple pictures with Picasso

I'm trying to download multiple pictures using picasso. here's my code:
for(int i=1; i <=20; i++){
String url = img_url + i + "/profile.jpg";
String img_dir = img_dir + i;
Picasso.with(this).load(url).into(picassoImageTarget(getApplicationContext(),img_dir, img_name));
}
Url of the site looks like this:
site.com/img/equipment/1/profile.jpg,
site.com/img/equipment/2/profile.jpg,
site.com/img/equipment/3/profile.jpg
and so on ...
i tried
Picasso.with(this).load(url).into(picassoImageTarget(getApplicationContext(),img_dir, img_name));
without the for loop and it is working. images are not download when i place it inside the loop.
here's my Target
private Target picassoImageTarget(Context context, final String imageDir, final String imageName) {
Log.d("picassoImageTarget", " picassoImageTarget");
ContextWrapper cw = new ContextWrapper(context);
final File directory = cw.getDir(imageDir, Context.MODE_PRIVATE); // path to /data/data/yourapp/app_imageDir
return new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
final File myImageFile = new File(directory, imageName); // Create image file
FileOutputStream fos = null;
try {
fos = new FileOutputStream(myImageFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Log.i("image", "image saved to >>>" + myImageFile.getAbsolutePath());
}
}).start();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
if (placeHolderDrawable != null) {}
}
};
}
please help. thanks.
Targets are held in WeakReferences.
You need to hold a reference to the Targets you want to keep to prevent them from being garbage collected.
Maybe your code would look something like:
final class MyLoader {
final ArrayList<Target> targets = new ArrayList<>(20);
void load(...) {
for(...) {
Target target = picassoImageTarget(...);
targets.add(target);
picasso.load(...).into(target); // TODO: Maybe remove from list when complete.
}
}
}

Get bitmap attached to fresco drawee? [duplicate]

I'm trying to replace Picasso in my android app with Fresco. However I am unsure of how to simply load a bitmap using Fresco.
With Picasso I would just do the following.
Bitmap poster = Picasso.with(getActivity())
.load(url)
.resize(Utils.convertDpToPixel(WIDTH,HEIGHT))
.centerCrop()
.get();
I have been unable to figure out how to create a Bitmap with this Fresco. Any ideas?
As Fresco said:
If your request to the pipeline is for a decoded image - an Android Bitmap, you can take advantage of our easier-to-use BaseBitmapDataSubscriber:
dataSource.subscribe(new BaseBitmapDataSubscriber() {
#Override
public void onNewResultImpl(#Nullable Bitmap bitmap) {
// You can use the bitmap in only limited ways
// No need to do any cleanup.
}
#Override
public void onFailureImpl(DataSource dataSource) {
// No cleanup required here.
}
},
executor);
You can not assign the bitmap to any variable not in the scope of the onNewResultImpl method.
http://frescolib.org/docs/datasources-datasubscribers.html#_
My code :
public void setDataSubscriber(Context context, Uri uri, int width, int height){
DataSubscriber dataSubscriber = new BaseDataSubscriber<CloseableReference<CloseableBitmap>>() {
#Override
public void onNewResultImpl(
DataSource<CloseableReference<CloseableBitmap>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<CloseableBitmap> imageReference = dataSource.getResult();
if (imageReference != null) {
final CloseableReference<CloseableBitmap> closeableReference = imageReference.clone();
try {
CloseableBitmap closeableBitmap = closeableReference.get();
Bitmap bitmap = closeableBitmap.getUnderlyingBitmap();
if(bitmap != null && !bitmap.isRecycled()) {
//you can use bitmap here
}
} finally {
imageReference.close();
closeableReference.close();
}
}
}
#Override
public void onFailureImpl(DataSource dataSource) {
Throwable throwable = dataSource.getFailureCause();
// handle failure
}
};
getBitmap(context, uri, width, height, dataSubscriber);
}
/**
*
* #param context
* #param uri
* #param width
* #param height
* #param dataSubscriber
*/
public void getBitmap(Context context, Uri uri, int width, int height, DataSubscriber dataSubscriber){
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
if(width > 0 && height > 0){
builder.setResizeOptions(new ResizeOptions(width, height));
}
ImageRequest request = builder.build();
DataSource<CloseableReference<CloseableImage>>
dataSource = imagePipeline.fetchDecodedImage(request, context);
dataSource.subscribe(dataSubscriber, UiThreadExecutorService.getInstance());
}
You would use Fresco's CacheKey directly for this:
public class DownloadVideoThumbnail extends AsyncTask<String, Void, Bitmap> {
private ImageView bmImage;
private Bitmap bitmapVideo;
private Context context;
public DownloadVideoThumbnail(Context context, ImageView bmImage) {
this.bmImage = (ImageView) bmImage;
this.context = context;
}
protected Bitmap doInBackground(String... urls) {
String urlStr = urls[0];
if (readFromCacheSync(urlStr) == null) {
try {
//Your method call here
bitmapVideo = retriveVideoFrameFromVideo(urlStr);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else {
bitmapVideo = readFromCacheSync(urlStr);
}
return null;
}
protected void onPostExecute(Bitmap result) {
if (bitmapVideo != null) {
//Load your bitmap here
bmImage.setImageBitmap(bitmapVideo);
bmImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
}
public void cacheBitmap(Bitmap bitmap, String url) {
try {
CacheKey cacheKey = new SimpleCacheKey(url);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
final byte[] byteArray = stream.toByteArray();
Fresco.getImagePipelineFactory().getMainFileCache().insert(cacheKey, new WriterCallback() {
#Override
public void write(OutputStream outputStream) throws IOException {
outputStream.write(byteArray);
}
});
} catch (IOException cacheWriteException) {
}
}
public static Bitmap readFromCacheSync(String imageUrl) {
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(imageUrl), null);
StagingArea stagingArea = StagingArea.getInstance();
EncodedImage encodedImage = stagingArea.get(cacheKey);
if (encodedImage != null) {
return BitmapFactory.decodeStream(encodedImage.getInputStream());
}
try {
return BitmapFactory.decodeStream(readFromDiskCache(cacheKey));
} catch (Exception e) {
return null;
}
}
private static InputStream readFromDiskCache(final CacheKey key) throws IOException {
try {
FileCache fileCache = ImagePipelineFactory.getInstance().getMainFileCache();
final BinaryResource diskCacheResource = fileCache.getResource(key);
if (diskCacheResource == null) {
FLog.v(TAG, "Disk cache miss for %s", key.toString());
return null;
}
PooledByteBuffer byteBuffer;
final InputStream is = diskCacheResource.openStream();
FLog.v(TAG, "Successful read from disk cache for %s", key.toString());
return is;
} catch (IOException ioe) {
return null;
}
}
public Bitmap retriveVideoFrameFromVideo(String videoPath) throws Throwable {
Bitmap bitmap = null;
MediaMetadataRetriever mediaMetadataRetriever = null;
try {
mediaMetadataRetriever = new MediaMetadataRetriever();
if (Build.VERSION.SDK_INT >= 14)
mediaMetadataRetriever.setDataSource(videoPath, new HashMap<String, String>());
else
mediaMetadataRetriever.setDataSource(videoPath);
bitmap = mediaMetadataRetriever.getFrameAtTime();
if (bitmap != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, stream);
cacheBitmap(bitmap, videoPath);
}
} catch (Exception e) {
e.printStackTrace();
throw new Throwable(
"Exception in retriveVideoFrameFromVideo(String videoPath)"
+ e.getMessage());
} finally {
if (mediaMetadataRetriever != null) {
mediaMetadataRetriever.release();
}
}
return bitmap;
}
}
You would use Fresco's image pipeline directly for this:
http://frescolib.org/docs/using-image-pipeline.html
Though if you don't mind my asking - what is the motivation here? Why do you need the Bitmap itself?
I found this solution using Kotlin's coroutines:
suspend fun getBitmapFromUri(imageUri: Uri): Bitmap = withContext(Dispatchers.Default) {
val imageRequest = ImageRequestBuilder.newBuilderWithSource(imageUri).build()
val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, this)
val result = DataSources.waitForFinalResult(dataSource) as CloseableReference<CloseableBitmap>
val bitmap = result.get().underlyingBitmap
CloseableReference.closeSafely(result)
dataSource.close()
return#withContext bitmap
}
Starting from this answer I created a quick implementation that uses Kotlin extensions and RxJava to get a ClosableBitmap from an ImageRequest:
fun ImageRequest.getBitmap(context: Context): Maybe<CloseableReference<CloseableBitmap>> {
val dataSource = Fresco.getImagePipeline().fetchDecodedImage(this, context)
return Maybe.create { emitter ->
dataSource.subscribe(
object : BaseDataSubscriber<CloseableReference<CloseableImage>>() {
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
emitter.onComplete()
}
override fun onNewResultImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
if (!dataSource.isFinished) {
return
}
dataSource.result
?.takeIf { it.get() is CloseableBitmap }
?.let {
#Suppress("UNCHECKED_CAST")
emitter.onSuccess(it as CloseableReference<CloseableBitmap>)
}
emitter.onComplete()
}
},
DefaultExecutorSupplier(1).forBackgroundTasks()
)
}
}
Since by contract it is required to close the reference once the bitmap has been used, I created this util function:
/**
* The bitmap passed into [block] is only valid during the execution of the method.
*/
fun <T> CloseableReference<CloseableBitmap>.useBitmap(block: (Bitmap?) -> T): T? {
return try {
this.get()?.underlyingBitmap?.let { block(it) }
} finally {
CloseableReference.closeSafely(this)
}
}

How check if a DiskLruCache already exists? (Android)

I´m using that way of cache Bitmaps in my app Using DiskLruCache in android 4.0 does not provide for openCache method
Thing is that I´m using that line in onCreate()
DiskLruImageCache dlic=new DiskLruImageCache(getApplicationContext(),"bckgCache", CACHESIZE, CompressFormat.PNG, 70);
and I´m pretty sure that It is overwriting my DiskLruCache everytime the app is opened "as new", so I´m not being able to recover some Bitmaps I catch las time user opened the app. So here is the question
How can I check I there´s already a DislLruCache created for an specific App so I will only create It If It doesn´t exist?
That's the class I'm using from the above URL
public class DiskLruImageCache {
private DiskLruCache mDiskCache;
private CompressFormat mCompressFormat = CompressFormat.PNG;
private int mCompressQuality = 70;
private static final int APP_VERSION = 1;
private static final int VALUE_COUNT = 1;
private static final String TAG = "DiskLruImageCache";
public DiskLruImageCache( Context context,String uniqueName, int diskCacheSize,
CompressFormat compressFormat, int quality ) {
try {
final File diskCacheDir = getDiskCacheDir(context, uniqueName );
mDiskCache = DiskLruCache.open( diskCacheDir, APP_VERSION, VALUE_COUNT, diskCacheSize );
mCompressFormat = compressFormat;
mCompressQuality = quality;
} catch (IOException e) {
e.printStackTrace();
}
}
private boolean writeBitmapToFile( Bitmap bitmap, DiskLruCache.Editor editor )
throws IOException, FileNotFoundException {
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream( editor.newOutputStream( 0 ), Utils.IO_BUFFER_SIZE );
return bitmap.compress( mCompressFormat, mCompressQuality, out );
} finally {
if ( out != null ) {
out.close();
}
}
}
private File getDiskCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath =
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!Utils.isExternalStorageRemovable() ?
Utils.getExternalCacheDir(context).getPath() :
context.getCacheDir().getPath();
return new File(cachePath + File.separator + uniqueName);
}
public void put( String key, Bitmap data ) {
DiskLruCache.Editor editor = null;
try {
editor = mDiskCache.edit( key );
if ( editor == null ) {
return;
}
if( writeBitmapToFile( data, editor ) ) {
mDiskCache.flush();
editor.commit();
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "image put on disk cache " + key );
}
} else {
editor.abort();
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + key );
}
}
} catch (IOException e) {
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "ERROR on: image put on disk cache " + key );
}
try {
if ( editor != null ) {
editor.abort();
}
} catch (IOException ignored) {
}
}
}
public Bitmap getBitmap( String key ) {
Bitmap bitmap = null;
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = mDiskCache.get( key );
if ( snapshot == null ) {
return null;
}
final InputStream in = snapshot.getInputStream( 0 );
if ( in != null ) {
final BufferedInputStream buffIn =
new BufferedInputStream( in, Utils.IO_BUFFER_SIZE );
bitmap = BitmapFactory.decodeStream( buffIn );
}
} catch ( IOException e ) {
e.printStackTrace();
} finally {
if ( snapshot != null ) {
snapshot.close();
}
}
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", bitmap == null ? "" : "image read from disk " + key);
}
return bitmap;
}
public boolean containsKey( String key ) {
boolean contained = false;
DiskLruCache.Snapshot snapshot = null;
try {
snapshot = mDiskCache.get( key );
contained = snapshot != null;
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( snapshot != null ) {
snapshot.close();
}
}
return contained;
}
public void clearCache() {
if ( BuildConfig.DEBUG ) {
Log.d( "cache_test_DISK_", "disk cache CLEARED");
}
try {
mDiskCache.delete();
} catch ( IOException e ) {
e.printStackTrace();
}
}
public File getCacheFolder() {
return mDiskCache.getDirectory();
}
And this is what I'm doing into my Activity, wich doesn't works. If you try offline works the first time, second It doesn't (null pointer in OnPause because It can't find any Bitmap in the folder). If you try Online always works, but, if you try online, and then offline, instead load the previous downloaded image, is stops (null pointer), so, main problem is that It, for whatever reason, doesn't records or reads anything in the cache folder
public class Portada extends Activity {
private LinearLayout linearLayout;
private BitmapDrawable drawableBitmap;
private Bitmap b;
private DiskLruImageCache dlic;
private final String urlFondo="http://adapp.hostei.com/img/portada.jpg";
private final int MAXMEMORY = (int) (Runtime.getRuntime().maxMemory() / 1024);
private final int CACHESIZE = MAXMEMORY / 8;
private final String KEYPORTADA="bckportada";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_portada);
linearLayout=(LinearLayout)findViewById(R.id.fondoPortada);
Log.i("OnCreate","Starting");
File cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"bckgCache");
if(!cacheDir.exists()){ // check if it exits. if not create one
Log.i("OnCreate","Create not exsisting folder");
cacheDir.mkdirs();
dlic=new DiskLruImageCache(Portada.this,cacheDir.getName(), CACHESIZE, CompressFormat.PNG, 70);
}
else{
dlic=new DiskLruImageCache(Portada.this,cacheDir.getName(), CACHESIZE, CompressFormat.PNG, 70);
}
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
Log.i("OnResume","Starting");
//checks if there's already a background image on cache
boolean hayportada=comprobarSiHayPortadaEnCache();
//creates a bckImage from R.drawable image if there's any already in cache
//this should only occurs once, the very first time the App runs
if(!hayportada){
b=BitmapFactory.decodeResource(getResources(), R.drawable.portada);
dlic.put(KEYPORTADA, b);
Log.i("onResume","Creates bckgImage from R.drawable");
}
//checks if there's any connection and if yes, loads the url image into cache and puts It as background
//if not load the image of the previous if
if(CheckOnline.isOnline(Portada.this)){
cargarPortadaUrl(urlFondo);//loads image from url and stores in cache
cargarImagenPortada(b);//put image as layout background
Log.i("onResume","there is online, down img");
}
else{
b=dlic.getBitmap(KEYPORTADA);
cargarImagenPortada(b);
Log.i("onResume","there's not online ");
}
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
dlic.put(KEYPORTADA, b);//just in case, It's already done in OnResume;
Log.i("onPause","stores Bitmap");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_portada, menu);
return true;
}
/**
* Takes an image from url and stores It in cache
*
*/
public void cargarPortadaUrl(String urlFondo){
DownloadImageTask dit=new DownloadImageTask();//Async task that downloads an img
try {
b=dit.execute(urlFondo).get();
dlic.put(KEYPORTADA, b);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//loads a Bitmap as Layout Background image
public void cargarImagenPortada(Bitmap bitm){
drawableBitmap=new BitmapDrawable(bitm);
linearLayout.setBackgroundDrawable(drawableBitmap);
}
//checks if there's any
public boolean comprobarSiHayPortadaEnCache(){
b=dlic.getBitmap(KEYPORTADA);
if(b==null)return false;
else return true;
}
}
Check if sd card is mounted. Get the path of the sdcard. Check if the folder under sdcard already exists, if not create one.
Remember to add permission in manifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
{
File cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"MyFolder");
if(!cacheDir.exists())
cacheDir.mkdirs();
}
You can use the below. Found this on developer site in the below link
File cacheDir = getDiskCacheDir(ActivityName.this, "thumbnails");
if(!cacheDir.exists()) // check if it exits. if not create one
{
cacheDir.mkdirs();
}
public static File getDiskCacheDir(Context context, String uniqueName) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath =
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
context.getCacheDir().getPath();
return new File(cachePath + File.separator + uniqueName);
}
For more information check the link below
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
I see you have used getAppliactionContext(). Check the link below
When to call activity context OR application context?. Get to know when to use activity context and getApplicationContext()
Edit:
File cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"MyFolder");
if(!cacheDir.exists()) // check if it exits. if not create one
{
cacheDir.mkdirs();
DiskLruImageCache dlic=new DiskLruImageCache(ActivityName.this,cacheDir, CACHESIZE, CompressFormat.PNG, 70);
}
else
{
DiskLruImageCache dlic=new DiskLruImageCache(ActivityName.this,cacheDir, CACHESIZE, CompressFormat.PNG, 70);
}
Edit: 2
As you can see below you are just passing the file not creating a new one.
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
this.directory = directory;
this.appVersion = appVersion;
this.journalFile = new File(directory, JOURNAL_FILE);
this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
this.valueCount = valueCount;
this.maxSize = maxSize;
}
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
throws IOException {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
if (valueCount <= 0) {
throw new IllegalArgumentException("valueCount <= 0");
}
// prefer to pick up where we left off
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
if (cache.journalFile.exists()) {
try {
cache.readJournal();
cache.processJournal();
cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true),
IO_BUFFER_SIZE);
return cache;
} catch (IOException journalIsCorrupt) {
System.logW("DiskLruCache " + directory + " is corrupt: "
+ journalIsCorrupt.getMessage() + ", removing");
cache.delete();
}
}
// create a new empty cache
directory.mkdirs();
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
cache.rebuildJournal();
return cache;
}

Categories

Resources