How check if a DiskLruCache already exists? (Android) - 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;
}

Related

Android: Notification stops updating once it has updated for a certain number of times on Kit-Kat

So I have a notification in my app. The notification has some text and an image which I fetch from a LruCache which I populate at the start. The problem is that on Kit-Kat devices (Moto E, XIomi) in my case, the notification stops updating if it has already updated a fixed number of times, lets say n (this n is usually fixed for each device, and is <10). This is my code for updating
String title = CommonUtils.getTitleFromID(id, context);
Bitmap bitmap = DataProvider.getInstance(context).diskLruImageCache.getBitmap(id + "");
if (playbackPaused) {
bigView.setImageViewResource(R.id.pause, R.drawable.pause_noti);
smallView.setImageViewResource(R.id.pause1, R.drawable.pause_noti);
remoteViews.setImageViewResource(R.id.pause2, R.drawable.pause_noti);
playbackPaused = false;
Log.d(TAG, "noti-false");
}
bigView.setTextViewText(R.id.title, title + "");
bigView.setImageViewBitmap(R.id.img, bitmap);
smallView.setTextViewText(R.id.title1, title);
smallView.setImageViewBitmap(R.id.img1, bitmap);
mNotificationManager.notify(NOTIFY_ID, notification);
I tried with a bit of debugging and all and I found that if I do not set the bitmap, (and just do
bitmap = null) then everything works fine.
I don't understand why this is happening. This issue is android version specific since I already tested on Nexus 5 (Lollipop) and other Android 5 phones but there this doesn't happen. Does someone have any idea what the reason behind this might be?
I am not expecting an exact situation. Even some ideas in the right direction will be very helpful. Thanks !!
I am also adding the code for my DiskLruCache in case that might be needed,
public class DiskLruImageCache {
private DiskLruCache mDiskCache;
private Bitmap.CompressFormat mCompressFormat = Bitmap.CompressFormat.JPEG;
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,
Bitmap.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 {
OutputStream 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 boolean writeUriToFile( Uri bitmap, DiskLruCache.Editor editor )
throws IOException, FileNotFoundException {
OutputStream out = null;
try {
out = new BufferedOutputStream( editor.newOutputStream( 0 ), Utils.IO_BUFFER_SIZE );
return true;
} 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 void put( String key, Uri data ) {
DiskLruCache.Editor editor = null;
try {
editor = mDiskCache.edit( key );
if ( editor == null ) {
return;
}
if( writeUriToFile( 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 synchronized 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 boolean removeKey( String key ) {
boolean removed=false;
DiskLruCache.Snapshot snapshot = null;
try {
removed = mDiskCache.remove( key );
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( snapshot != null ) {
snapshot.close();
}
}
return removed;
}
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();
}
}
put if condition for kitkat and lower versions ... becoz after kitkat version changes in color in notification system.. my mipmap notify img siz is 96*96
NOTIFICATION_ID= Integer.parseInt(arr_msg[7].toString());
mBuilder.setSmallIcon(R.mipmap.alert_nodification_icon)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.alert_nodification_icon))
.setContentTitle(notification_vehicle_no)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(notification_msg))
.setContentText(notification_msg);}
mBuilder.setContentIntent(contentIntent);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
mNotificationManager.notify(NOTIFICATION_ID,notification);

Create downloadable custom theme and apply it during run time

I'm making an Android app that needs to allow client to maintain the resources from their server which would include strings, drawables etc.
I've already created a mechanism for downloading a zip file with all these files, and they're able to change strings pretty easy, I've also created a mechanism that allows the client to change bg color for UI controls, to change width, height etc but I have a feeling that there must be a better way to create all this.
So I believe the real question is:
What's the best practice to create a custom theme, deploy it on server, make the app download it, and apply it to app afterwards?
I know how to create custom theme and how to deploy it with the app, and how to apply it during runtime, but the problem here is that resources are pre-compiled and once you create APK there's no way for developer to change them which would be required in order to add new themes/drawables/styles/strings.
Do I need to create a custom mechanism for all this (loading images, styles, strings etc from the file system) and to apply them during runtime by creating my own controls that would do that in constructor for example or is there a way to do this properly :)? ( how does Swiftkey do this with all the keyboard themes, and how do similar apps do it allowing the users to download theme and apply it after that )?
I'm sorry if I didn't see similar question, I really tried to find an answer myself during past 2 days, but I failed to find anything useful, so this is my last chance to get a constructive answer :).
The closest to solution i need was this answer: Changing app theme at runtime using using external theme file but I've already made that functionality, and i know i can change colors like that, but the problem is that i would like to be able to change things like borders, on button pressed state etc that require resources other than simple color value :(.
Thanks heaps!
P.S. I've also read about the extension files so is that something i need to consider while thinking about this, or do i need to look elsewhere? The problem with obb files is that they must be deployed over PlayStore and that's not "perfect" for the client because they need to pack it by using jobb, and to deploy it to PlayStore which is too technical for them, so they would prefer creating a zip file, putting it on server, and the app should do the rest :).
I've finally decided to solve this by making a custom system for handling drawables, strings etc so now i have a custom class called "ResourceManager" that handles what needs to be loadad and how, and themes are distributed as a zip file which app downloads, extracts and later uses.
I had to compile nine patch images by myself before putting them in zip file, and I did that using "abrc" from here: http://forum.xda-developers.com/showthread.php?t=785012
I've also created a simple bash script that goes recursively through custom folder and compiles all nine patch images with abrc.
I've also created a simple helper in the ResourceManager that checks and tells me the screen density so i can normally support images in hdpi, xhdpi etc densities, and finally i don't re-create the images every time i need them, i save them in a static list of HashMap so i can reuse the ones I've already created and that way i hope to prevent wasting too much phone's memory :).
OK that's all in short lines, if anyone has any questions please let me know, i'll be glad to share this experience with anyone.
Cheers!
============ EDIT ============
Here's the class I ended up writing for this purpose (it downloads the file, checks for it's version, loads strings from JSON file rather than strings.xml etc)
NOTE: This is not a full class so some parts are missing, but I think it's more than enough to get the idea how I solved all this :)
/**
* Created by bojank on 7/28/2014.
* Class that handles custom resources downloaded from server
*/
public class ResourceManager {
// List of ninePatchImages in the application
private static ArrayList<HashMap<String, NinePatchDrawable>> ninePatchHashMaps;
private static ArrayList<HashMap<String, Drawable>> imagesHashMaps;
private static ImageLoader imageLoader;
// Context for methods
public static Context ctx;
// JSONObject with all strings
private static JSONObject joString;
// JSONObject with all styles
private static JSONObject joStyles;
// String with current active lang code
private static String currentLanguage;
private static String sdcardPath;
// Private consturctor to prevent creating a class instance
private ResourceManager() {
}
/**
* Method that returns a translated string for given key
*
* #param key String
* #return String
*/
public static String getString(String module, String key) {
String output = ""; //String.format("[%s - %s]", module, key);
try {
if (getStringsFile() != null && getStringsFile().getJSONObject(module).has(key))
output = getStringsFile().getJSONObject(module).getString(key);
} catch (Exception e) {
// Force some default language if proper json file is missing for newly added language
currentLanguage = "en-US";
Helper.saveLocale(currentLanguage, ctx);
Helper.logError("ErrorFetchingString", e);
}
return output;
}
/**
* Method that returns JSONObject with string resources
* #return JSONObject
* #throws JSONException
*/
public static JSONObject getStringsFile() throws JSONException {
if (joString == null) {
String stringFileName = getResourcesPath() + "languages/" + getCurrentLanguage() + "/values.json";
String languageFile = Helper.readJsonFile(stringFileName);
if (languageFile != null) {
joString = new JSONObject(Helper.readJsonFile(stringFileName));
} else {
return null;
}
}
return joString.getJSONObject("strings");
}
/**
* Method that returns current language ("sr", "en"...)
* #return String
*/
public static String getCurrentLanguage() {
if (currentLanguage == null)
currentLanguage = Helper.getCurrentLanguage(ctx);
return currentLanguage;
}
/**
* Method that resets joString object and currentLanguage on language change
*/
public static void resetLanguage() {
joString = null;
currentLanguage = null;
}
/**
* Method that resets joStyles object on theme change
*/
public static void resetStyle() {
joStyles = null;
}
/**
* Method that deletes a directory from filesystem
* #param path File
* #return boolean
*/
public static boolean deleteDirectory(File path) {
if( path.exists() ) {
File[] files = path.listFiles();
for(int i=0; i<files.length; i++) {
if(files[i].isDirectory()) {
deleteDirectory(files[i]);
}
else {
files[i].delete();
}
}
}
return(path.delete());
}
/**
* Method that get's the version of assets file
* #param url String
*/
public static String getAssetsVersion(String url) throws IOException {
Helper.logInfo("REQUEST URL:", url);
OkHttpClient client = new OkHttpClient();
// set connection timeut to 5min
client.setConnectTimeout(1, TimeUnit.MINUTES);
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
/**
* Method that downloads assets file from server
* #param url String
* #return String
* #throws IOException
*/
public static String getAssetsFile(String url) throws IOException {
Helper.logInfo("REQUEST URL:", url);
OkHttpClient client = new OkHttpClient();
// set connection timeut to 5min
client.setConnectTimeout(1, TimeUnit.MINUTES);
Request request = new Request.Builder()
.url(url)
.header("User-Agent", MyApplication.USER_AGENT)
.build();
Response response = client.newCall(request).execute();
InputStream inputStreamFile = response.body().byteStream();
try {
// Output stream
String outputFileName = Environment.getExternalStorageDirectory().toString() + "/assets.zip";
File deleteFile = new File(outputFileName);
deleteFile.delete();
OutputStream output = new FileOutputStream(outputFileName);
byte data[] = new byte[1024];
int count;
// writing data to file
while ((count = inputStreamFile.read(data)) != -1)
output.write(data, 0, count);
// flushing output
output.flush();
// closing streams
output.close();
inputStreamFile.close();
return outputFileName;
} catch (Exception e) {
Helper.logError("Download Resursa", e);
return "ERROR";
}
}
public static void setStyle(View v, String styleName) {
try {
if (styleName == null || styleName.equals("")) {
if (v instanceof EditText)
processStyle(v, getStylesFile().getJSONObject("EditText"));
} else
processStyle(v, getStylesFile().getJSONObject(styleName));
} catch (Exception e) {
Helper.logError("Setting Styles", e);
}
}
private static void setBackground(View v, Drawable d) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
v.setBackgroundDrawable(d);
} else {
v.setBackground(d);
}
}
public static JSONObject getStylesFile() throws JSONException {
if (joStyles == null) {
String stylesFileName = getResourcesPath() + "styles/properties.json";
joStyles = new JSONObject(Helper.readJsonFile(stylesFileName));
}
return joStyles;
}
public static void processStyle(View v, JSONObject joStyle) {
if(joStyle != null) {
try {
// used for layout margins
LinearLayout.LayoutParams layoutParams = null;
if (Helper.isValidParameter(joStyle, "backgroundColor"))
v.setBackgroundColor(Color.parseColor(joStyle.getString("backgroundColor")));
if (Helper.isValidParameter(joStyle, "backgroundImage"))
setBackground(v, loadNinePatchFromFilesystem(getImagesPath() + joStyle.getString("backgroundImage")));
if (v instanceof TextView) {
applyTextViewParameters(v, joStyle);
} else if (v instanceof ListView) {
if (Helper.isValidParameter(joStyle, "dividerColor")) {
((ListView) v).setDivider(new ColorDrawable(Color.parseColor(joStyle.getString("dividerColor"))));
((ListView) v).setDividerHeight(Helper.convertDpToPixel(1));
}
if (Helper.isValidParameter(joStyle, "dividerHeight")) {
((ListView) v).setDividerHeight(Helper.convertDpToPixel(joStyle.getInt("dividerHeight")));
}
} else if (v instanceof UnderlinePageIndicator) {
if (Helper.isValidParameter(joStyle, "backgroundColor")) {
v.setBackgroundColor(Color.parseColor(joStyle.getString("backgroundColor")));
}
if (Helper.isValidParameter(joStyle, "selectedColor")) {
((UnderlinePageIndicator) v).setSelectedColor(Color.parseColor(joStyle.getString("selectedColor")));
}
} else if (v instanceof StyleableBackground) {
if (Helper.isValidParameter(joStyle, "backgroundColor")) {
View background = v.findViewById(R.id.llBackground);
if (background != null) {
background.setBackgroundColor(Color.parseColor(joStyle.getString("backgroundColor")));
}
}
if (Helper.isValidParameter(joStyle, "borderTopColor")) {
View topBorder = v.findViewById(R.id.llTopBorder);
if (topBorder != null) {
topBorder.setBackgroundColor(Color.parseColor(joStyle.getString("borderTopColor")));
if (Helper.isValidParameter(joStyle, "borderTopHeight")) {
topBorder.setMinimumHeight(Helper.convertDpToPixel(joStyle.getInt("borderTopHeight")));
}
}
}
if (Helper.isValidParameter(joStyle, "borderBottomColor")) {
View bottomBorder = v.findViewById(R.id.llBottomBorder);
if (bottomBorder != null) {
bottomBorder.setBackgroundColor(Color.parseColor(joStyle.getString("borderBottomColor")));
if (Helper.isValidParameter(joStyle, "borderBottomHeight")) {
bottomBorder.setMinimumHeight(Helper.convertDpToPixel(joStyle.getInt("borderBottomHeight")));
}
}
}
if (Helper.isValidParameter(joStyle, "backgroundImage")) {
ImageView ivBackgroundImage = (ImageView) v.findViewById(R.id.ivBackgroundImage);
if (ivBackgroundImage != null) {
BitmapDrawable d = (BitmapDrawable) ResourceManager.loadImageFromFilesystem(ResourceManager.getImagesPath() + joStyle.getString("backgroundImage"));
d.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
d.setGravity(Gravity.FILL_HORIZONTAL | Gravity.FILL_VERTICAL);
setBackground(ivBackgroundImage, d);
}
}
}
if(Helper.isValidParameter(joStyle, "width"))
v.setMinimumWidth(joStyle.getInt("width"));
if(Helper.isValidParameter(joStyle, "height"))
v.setMinimumHeight(joStyle.getInt("height"));
if(Helper.isValidParameter(joStyle, "padding"))
v.setPadding(joStyle.getInt("padding"), joStyle.getInt("padding"), joStyle.getInt("padding"), joStyle.getInt("padding"));
if(Helper.isValidParameter(joStyle, "paddingLeft"))
v.setPadding(joStyle.getInt("paddingLeft"), v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom());
if(Helper.isValidParameter(joStyle, "paddingTop"))
v.setPadding(v.getPaddingLeft(), joStyle.getInt("paddingTop"), v.getPaddingRight(), v.getPaddingBottom());
if(Helper.isValidParameter(joStyle, "paddingRight"))
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), joStyle.getInt("paddingRight"), v.getPaddingBottom());
if(Helper.isValidParameter(joStyle, "paddingBottom"))
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), joStyle.getInt("paddingBottom"));
if(Helper.isValidParameter(joStyle, "margin")) {
layoutParams = new LinearLayout.LayoutParams(v.getLayoutParams());
layoutParams.setMargins(joStyle.getInt("margin"), joStyle.getInt("margin"), joStyle.getInt("margin"), joStyle.getInt("margin"));
}
if(Helper.isValidParameter(joStyle, "marginLeft")) {
layoutParams = new LinearLayout.LayoutParams(v.getLayoutParams());
layoutParams.setMargins(joStyle.getInt("marginLeft"), layoutParams.topMargin, layoutParams.rightMargin, layoutParams.bottomMargin);
}
if(Helper.isValidParameter(joStyle, "marginTop")) {
layoutParams = new LinearLayout.LayoutParams(v.getLayoutParams());
layoutParams.setMargins(layoutParams.leftMargin, joStyle.getInt("marginTop"), layoutParams.rightMargin, layoutParams.bottomMargin);
}
if(Helper.isValidParameter(joStyle, "marginRight")) {
layoutParams = new LinearLayout.LayoutParams(v.getLayoutParams());
layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin, joStyle.getInt("marginRight"), layoutParams.bottomMargin);
}
if(layoutParams != null)
v.setLayoutParams(layoutParams);
RelativeLayout.LayoutParams relativeLayoutParams = null;
if (Helper.isValidParameter(joStyle, "alignParentTop") && joStyle.getBoolean("alignParentTop")) {
relativeLayoutParams = new RelativeLayout.LayoutParams(v.getLayoutParams());
relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
}
if (Helper.isValidParameter(joStyle, "alignParentLeft") && joStyle.getBoolean("alignParentLeft")) {
relativeLayoutParams = new RelativeLayout.LayoutParams(v.getLayoutParams());
relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
}
if (Helper.isValidParameter(joStyle, "alignParentBottom") && joStyle.getBoolean("alignParentBottom")) {
relativeLayoutParams = new RelativeLayout.LayoutParams(v.getLayoutParams());
relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
}
if (Helper.isValidParameter(joStyle, "alignParentRight") && joStyle.getBoolean("alignParentRight")) {
relativeLayoutParams = new RelativeLayout.LayoutParams(v.getLayoutParams());
relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
}
if(Helper.isValidParameter(joStyle, "marginLeft")) {
relativeLayoutParams = new RelativeLayout.LayoutParams(v.getLayoutParams());
relativeLayoutParams.setMargins(joStyle.getInt("marginLeft"), relativeLayoutParams.topMargin, relativeLayoutParams.rightMargin, relativeLayoutParams.bottomMargin);
}
if(Helper.isValidParameter(joStyle, "marginTop")) {
relativeLayoutParams = new RelativeLayout.LayoutParams(v.getLayoutParams());
relativeLayoutParams.setMargins(relativeLayoutParams.leftMargin, joStyle.getInt("marginTop"), relativeLayoutParams.rightMargin, relativeLayoutParams.bottomMargin);
}
if(Helper.isValidParameter(joStyle, "marginRight")) {
relativeLayoutParams = new RelativeLayout.LayoutParams(v.getLayoutParams());
relativeLayoutParams.setMargins(relativeLayoutParams.leftMargin, relativeLayoutParams.topMargin, joStyle.getInt("marginRight"), relativeLayoutParams.bottomMargin);
}
if (relativeLayoutParams != null) {
v.setLayoutParams(relativeLayoutParams);
}
} catch (Exception e) {
Helper.logError("", e);
}
}
}
public static String getSdcardPath() {
if(sdcardPath == null)
sdcardPath = ctx.getApplicationInfo().dataDir;
return sdcardPath;
}
public static String getResourcesPath() {
return getSdcardPath() + "/resources/";
}
public static String getCSSPath() {
return getResourcesPath() + "default.css";
}
public static String getImagesPath() {
return getResourcesPath() + "images/" + ResourceConstants.getScreenDPI(ctx) + "/";
}
public static String getImagesPathNoDpi() {
return getResourcesPath() + "images/";
}
public static NinePatchDrawable loadNinePatchFromFilesystem(String filename) {
if(ninePatchHashMaps == null)
ninePatchHashMaps = new ArrayList<HashMap<String, NinePatchDrawable>>();
// check if we already have this filename so we can reuse it
for (int i = 0; i < ninePatchHashMaps.size(); i++) {
HashMap<String, NinePatchDrawable> row = ninePatchHashMaps.get(i);
if(row.containsKey(filename))
return row.get(filename);
}
NinePatchDrawable patchy = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(filename, options);
byte[] chunk = bitmap.getNinePatchChunk();
boolean result = NinePatch.isNinePatchChunk(chunk);
if (result)
patchy = new NinePatchDrawable(bitmap, chunk, new Rect(), null);
} catch (Exception e){
Helper.logError("NinePatchLoading",e);
}
if(patchy != null) {
HashMap<String, NinePatchDrawable> drawableImage = new HashMap<String, NinePatchDrawable>();
drawableImage.put(filename, patchy);
ninePatchHashMaps.add(drawableImage);
}
return patchy;
}
public static Drawable loadImageFromFilesystem(String filename) {
if(imagesHashMaps == null)
imagesHashMaps = new ArrayList<HashMap<String, Drawable>>();
// check if we already have this filename so we can reuse it
for (int i = 0; i < imagesHashMaps.size(); i++) {
HashMap<String, Drawable> row = imagesHashMaps.get(i);
if(row.containsKey(filename))
return row.get(filename);
}
Drawable image = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(filename, options);
if(bitmap == null)
bitmap = BitmapFactory.decodeFile(filename.replace(ResourceConstants.getScreenDPI(ctx) + "/", ""), options);
image = new BitmapDrawable(bitmap);
} catch (Exception e){
Helper.logError("ImageLoadingError",e);
}
if(image != null) {
HashMap<String, Drawable> drawableImage = new HashMap<String, Drawable>();
drawableImage.put(filename, image);
imagesHashMaps.add(drawableImage);
}
return image;
}
}

Using Picasso with custom disk cache

In Volley library, the NetworkImageView class requires an ImageLoader that handles all the image requests by searching for them inside an ImageCache implementation, the user is free to choose how the cache should work, the location and the name of the images.
I'm switching from Volley to Retrofit, and for the images I decided to try Picasso.
With the former library, I had a String parameter in each of my items containing the image URL, then I used myNetworkImageView.setImageUrl(item.getURL()) and it was able to determine if image was cached on disk. If the image existed in cache folder, the image was loaded, otherwise it was downloaded and loaded.
I would like to be able to do the same with Picasso, is it possible with Picasso APIs or should I code such feature by myself?
I was thinking to download the image to a folder (the cache folder), and use Picasso.with(mContext).load(File downloadedimage) on completion. Is this the proper way or are there any best practices?
Picasso doesn't have a disk cache. It delegates to whatever HTTP client you are using for that functionality (relying on HTTP cache semantics for cache control). Because of this, the behavior you seek comes for free.
The underlying HTTP client will only download an image over the network if one does not exist in its local cache (and that image isn't expired).
That said, you can create custom cache implementation for java.net.HttpUrlConnection (via ResponseCache or OkHttp (via ResponseCache or OkResponseCache) which stores files in the format you desire. I would strongly advise against this, however.
Let Picasso and the HTTP client do the work for you!
You can call setIndicatorsEnabled(true) on the Picasso instance to see an indicator from where images are being loaded. It looks like this:
If you never see a blue indicator, it's likely that your remote images do not include proper cache headers to enable caching to disk.
If your project is using the okhttp library then picasso will automatically use it as the default downloader and the disk caché will work automagically.
Assuming that you use Android Studio, just add these two lines under dependencies in the build.gradle file and you will be set. (No extra configurations with picasso needed)
dependencies {
[...]
compile 'com.squareup.okhttp:okhttp:2.+'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.+'
}
As rightly pointed out by many people here, OkHttpClient is the way to go for caching.
When caching with OkHttp you might also want to gain more control on Cache-Control header in the HTTP response using OkHttp interceptors, see my response here
How it is was written previously, Picasso uses a cache of the underlying Http client.
HttpUrlConnection's built-in cache isn't working in truly offline mode and If using of OkHttpClient is unwanted by some reasons, it is possible to use your own implementation of disk-cache (of course based on DiskLruCache).
One of ways is subclassing com.squareup.picasso.UrlConnectionDownloader and programm whole logic at:
#Override
public Response load(final Uri uri, int networkPolicy) throws IOException {
...
}
And then use your implementation like this:
new Picasso.Builder(context).downloader(<your_downloader>).build();
Here is my implementation of UrlConnectionDownloader, that works with disk-cache and ships to Picasso bitmaps even in total offline mode:
public class PicassoBitmapDownloader extends UrlConnectionDownloader {
private static final int MIN_DISK_CACHE_SIZE = 5 * 1024 * 1024; // 5MB
private static final int MAX_DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
#NonNull private Context context;
#Nullable private DiskLruCache diskCache;
public class IfModifiedResponse extends Response {
private final String ifModifiedSinceDate;
public IfModifiedResponse(InputStream stream, boolean loadedFromCache, long contentLength, String ifModifiedSinceDate) {
super(stream, loadedFromCache, contentLength);
this.ifModifiedSinceDate = ifModifiedSinceDate;
}
public String getIfModifiedSinceDate() {
return ifModifiedSinceDate;
}
}
public PicassoBitmapDownloader(#NonNull Context context) {
super(context);
this.context = context;
}
#Override
public Response load(final Uri uri, int networkPolicy) throws IOException {
final String key = getKey(uri);
{
Response cachedResponse = getCachedBitmap(key);
if (cachedResponse != null) {
return cachedResponse;
}
}
IfModifiedResponse response = _load(uri);
if (cacheBitmap(key, response.getInputStream(), response.getIfModifiedSinceDate())) {
IfModifiedResponse cachedResponse = getCachedBitmap(key);
if (cachedResponse != null) {return cachedResponse;
}
}
return response;
}
#NonNull
protected IfModifiedResponse _load(Uri uri) throws IOException {
HttpURLConnection connection = openConnection(uri);
int responseCode = connection.getResponseCode();
if (responseCode >= 300) {
connection.disconnect();
throw new ResponseException(responseCode + " " + connection.getResponseMessage(),
0, responseCode);
}
long contentLength = connection.getHeaderFieldInt("Content-Length", -1);
String lastModified = connection.getHeaderField(Constants.HEADER_LAST_MODIFIED);
return new IfModifiedResponse(connection.getInputStream(), false, contentLength, lastModified);
}
#Override
protected HttpURLConnection openConnection(Uri path) throws IOException {
HttpURLConnection conn = super.openConnection(path);
DiskLruCache diskCache = getDiskCache();
DiskLruCache.Snapshot snapshot = diskCache == null ? null : diskCache.get(getKey(path));
if (snapshot != null) {
String ifModifiedSince = snapshot.getString(1);
if (!isEmpty(ifModifiedSince)) {
conn.addRequestProperty(Constants.HEADER_IF_MODIFIED_SINCE, ifModifiedSince);
}
}
return conn;
}
#Override public void shutdown() {
try {
if (diskCache != null) {
diskCache.flush();
diskCache.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
super.shutdown();
}
public boolean cacheBitmap(#Nullable String key, #Nullable InputStream inputStream, #Nullable String ifModifiedSince) {
if (inputStream == null || isEmpty(key)) {
return false;
}
OutputStream outputStream = null;
DiskLruCache.Editor edit = null;
try {
DiskLruCache diskCache = getDiskCache();
edit = diskCache == null ? null : diskCache.edit(key);
outputStream = edit == null ? null : new BufferedOutputStream(edit.newOutputStream(0));
if (outputStream == null) {
return false;
}
ChatUtils.copy(inputStream, outputStream);
outputStream.flush();
edit.set(1, ifModifiedSince == null ? "" : ifModifiedSince);
edit.commit();
return true;
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (edit != null) {
edit.abortUnlessCommitted();
}
ChatUtils.closeQuietly(outputStream);
}
return false;
}
#Nullable
public IfModifiedResponse getCachedBitmap(String key) {
try {
DiskLruCache diskCache = getDiskCache();
DiskLruCache.Snapshot snapshot = diskCache == null ? null : diskCache.get(key);
InputStream inputStream = snapshot == null ? null : snapshot.getInputStream(0);
if (inputStream == null) {
return null;
}
return new IfModifiedResponse(inputStream, true, snapshot.getLength(0), snapshot.getString(1));
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Nullable
synchronized public DiskLruCache getDiskCache() {
if (diskCache == null) {
try {
File file = new File(context.getCacheDir() + "/images");
if (!file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.mkdirs();
}
long maxSize = calculateDiskCacheSize(file);
diskCache = DiskLruCache.open(file, BuildConfig.VERSION_CODE, 2, maxSize);
}
catch (Exception e) {
e.printStackTrace();
}
}
return diskCache;
}
#NonNull
private String getKey(#NonNull Uri uri) {
String key = md5(uri.toString());
return isEmpty(key) ? String.valueOf(uri.hashCode()) : key;
}
#Nullable
public static String md5(final String toEncrypt) {
try {
final MessageDigest digest = MessageDigest.getInstance("md5");
digest.update(toEncrypt.getBytes());
final byte[] bytes = digest.digest();
final StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) {
sb.append(String.format("%02X", aByte));
}
return sb.toString().toLowerCase();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
static long calculateDiskCacheSize(File dir) {
long available = ChatUtils.bytesAvailable(dir);
// Target 2% of the total space.
long size = available / 50;
// Bound inside min/max size for disk cache.
return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
}
}

how to save log cat all message during testing of application

My application is running fine but when it went in testing,it have some issue somewhere it got crashed and some issue also happens my question is how can i get all logs of my application in testing phase from device when device is not connection to computer because tester not use eclipse.
please help me to resolve this. Thanks in advance for any help.
You should use a crash report library like BugSense or Accra.
This kind of libs mimics the Android market feature of released apps, but during testing phase : you can get complete crash reports, with stack traces and other data (first time/last time of bug occurence, device model, etc.)
If you really want log. You can use the code below:
logcatProc = Runtime.getRuntime().exec(cmds);
mReader = new BufferedReader(new InputStreamReader(logcatProc.getInputStream()), 1024);
String line = null;
while ((line = mReader.readLine()) != null) {
if (line.length() == 0) {
continue;
}
if (out != null && line.contains(mPID)) {
out.write((simpleDateFormat2.format(new Date()) + " " + line + "\n").getBytes());
}
}
cmds = "logcat *:e *:i | grep \"(" + mPID + ")\"";
you can use your own grep format.
Tips: The logcat will be flushed off in a while
so you should put above code in a thread
You should try android-logging-log4j.
By the help of this Api you can record all the crash log in form of Text, Xml format and will be stored in the path you will provide like Phone memory or SD card.
So even if device is in Offline mode all the crash entry will be recorded over there. So you can get from that device and go through it for debugging.
Hope this will help you.
You have to use this code to get your own project logs.
public class LogcatFileManager {
private static LogcatFileManager INSTANCE = null ;
private static String PATH_LOGCAT;
private LogDumper mLogDumper = null ;
private int MPID;
private SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat ( "yyyyMMdd" );
private SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat ( "yyyy-MM-dd HH: mm: SS" );
public static LogcatFileManager getInstance () {
if (INSTANCE == null ) {
INSTANCE = new LogcatFileManager ();
}
return INSTANCE;
}
private LogcatFileManager () {
MPID = android.os.Process.myPid ();
}
private void setFolderPath (String folderPath) {
File folder = new File (folderPath);
if (! folder.exists ()) {
folder.mkdirs ();
}
if (! folder.isDirectory ())
throw new IllegalArgumentException ( "The folder path is Not a logcat Directory:" + folderPath);
PATH_LOGCAT = folderPath.endsWith("/") ? folderPath : folderPath + "/";
}
public void start (String saveDirectoy) {
setFolderPath (saveDirectoy);
if (mLogDumper == null )
mLogDumper = new LogDumper (String.valueOf (MPID), PATH_LOGCAT);
mLogDumper.start ();
}
public void stop () {
if (mLogDumper!=null ) {
mLogDumper.stopLogs();
mLogDumper = null ;
}
}
public class LogDumper extends Thread {
private Process logcatProc;
private BufferedReader MReader = null ;
private boolean mRunning = true ;
String cmds = null ;
private String MPID;
private FileOutputStream out = null ;
public LogDumper (String pid, String dir) {
MPID = pid;
try {
out = new FileOutputStream (new File(dir, "logcat-" + simpleDateFormat1.format (new Date ()) +".log"),true);
} catch (FileNotFoundException e) {
e.printStackTrace ();
}
cmds = "logcat *:e *:i | grep \"(" + MPID + ")\"";
}
public void stopLogs () {
mRunning = false ;
}
#Override
public void run() {
// TODO Auto-generated method stub
try {
logcatProc = Runtime.getRuntime().exec(cmds);
MReader = new BufferedReader ( new InputStreamReader (logcatProc.getInputStream ()), 1024 );
String line = null ;
while (mRunning && (line=MReader.readLine())!=null ) {
if (! mRunning) {
break ;
}
if (line.length () == 0 ) {
continue ;
}
if (out!=null && line.contains (MPID)) {
out.write ((simpleDateFormat2.format(new Date())+""+line+"\n").getBytes());
}
}
} catch (IOException e) {
e.printStackTrace ();
} finally {
if (logcatProc!=null ) {
logcatProc.destroy();
logcatProc = null ;
}
if (MReader!=null) {
try {
MReader.close ();
MReader = null ;
} catch (IOException e) {
e.printStackTrace ();
}
}
if (out!=null) {
try {
out.close ();
} catch (IOException e) {
e.printStackTrace ();
}
out = null ;
}
}
}
}
}
crashlytics is something you need: http://try.crashlytics.com/
You will be informed about errors, version of app that crashed etc...

Saving and Reading Bitmaps/Images from Internal memory in 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
}

Categories

Resources