I am currently using Picasso to load image from server side and save it in Internal storage in Android.
I am using the following code to load images from server side:
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.post(new Runnable() {
#Override
public void run() {
System.out.println("start run.....");
Picasso.with(context)
.load(url)
.resize(10, 10)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
System.out.println("start picasso....");
if (bitmap != null) {
// save image in internal memory
String directory = saveToInternalStorage(bitmap, name);
System.out.println(directory);
} else
System.out.println("image return is null.....");
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
System.out.println("Failure in loading photo from server: " + name);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
and the following code to save image in memory:
private String saveToInternalStorage(Bitmap bitmapImage, String imageName){
System.out.println("start saving image......");
ContextWrapper cw = new ContextWrapper(context);
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,imageName);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
boolean save=bitmapImage.compress(Bitmap.CompressFormat.PNG, 2, fos);
System.out.println(save);
fos.flush();
fos.close();
} catch (Exception e) {
System.out.println("Error in saving photo "+e.toString());
}
System.out.println("Image is successfully saved..."+directory.getAbsolutePath());
return directory.getAbsolutePath();
}
However, my problem is with Garbage Collection. Picasso does not start at all, even I do not get any failure message from Picasso, and I face with following error :
D/dalvikvm: GC_CONCURRENT freed 434K, 11% free 12767K/14215K, paused 14ms+25ms, total 118ms
I would be thankful, if anyone suggest me any solution to avoid this error.
this is not error instead this is information from GC saying GC_CONCURRENT has freed memory which is 434K and took 25ms. There is Google IO talk I would recommend you watch it
"Picasso does not start at all". Are you not able to load image at all ?
I am not sure if you are facing any problem regarding loading of the image or saving to your internal storage. As much I can guess you are able to do it and the message which you think is error is your problem.
If I am not getting it right. I would pledge you to draft you question in more specified way.
hope this will help!
Related
I'm trying to save the frame of the image from the live stream video. So, I'm able to show live stream video from my android application as well as saving it in my local storage. Now, I want to use some sort of delay in my saveImage function so that images get saved after some specific time. I have used both Handler and TimerTask. The image is getting saved in my local directory after some delay but the length of the image that I get is sometimes very small, the other time normal. I want my saved image to exactly the length of the video stream that I am getting in my application.
I hope the question I asked is easy to understand. I am a beginner in both android and stack overflow.
P.S - I used mjpeg library for showing the video. The video I am getting is from an IP Camera.
Code for saving the images
public void saveImage(){
try {
photo =
new File(Environment.getExternalStorageDirectory(),
"Download/photos/photo" + Instant.now().getEpochSecond() + ".jpg");
if (photo.exists()) {
photo.delete();
}
System.out.println("Photo " + photo);
FileOutputStream fos = new FileOutputStream(photo.getPath());
System.out.println("Image_length" +image.length);
fos.write(image);
fos.close();
} catch (IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
Code where saveImage is called
final Bitmap outputImg = BitmapFactory.decodeByteArray(image, 0, image.length);
if (outputImg != null) {
if (run) {
newFrame(outputImg);
// Saving frames in internal Storage
new Timer().schedule(
new TimerTask() {
#Override
public void run() {
saveImage();
}
},5000
);
}
} else {
Log.e(tag, "Read image error");
}
#Override
public void onBindViewHolder(final ViewHolder holder ,int position) {
Glide.with(c)
.load(images.get(position))
.placeholder(R.mipmap.ic_launcher)
.into(holder.img);
holder.img.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try{
String fileName = "bitmap.png";
FileOutputStream stream = c.openFileOutput(fileName,Context.MODE_PRIVATE);
Intent showBigPicture = new Intent(c,showBigPicture.class);
Bitmap bitmapImage = BitmapFactory.decodeFile(images.get(position));
bitmapImage.compress(Bitmap.CompressFormat.PNG,100,stream);
stream.close();
bitmapImage.recycle();
showBigPicture.putExtra("image",fileName);
c.startActivity(showBigPicture);
}catch (Exception e){
e.printStackTrace();
}
}
});
}
this is showing in logCat " Unable to decode stream: java.io.FileNotFoundException: android.support.v7.widget.AppCompatImageView{e22d977 V.ED..C. ...P.... 0,0-540,890 #7f0b0061 app:id/img}: open failed: ENOENT (No such file or directory)"
I believe you want to follow this answer on saving Bitmap images. I believe the reason you're getting a FileNotFoundException is because you're providing the URI to a file that doesn't exist yet to the decodeFile function that's quite possibly a URL from what I can tell. In short, to save a bitmap:
Create a new File(filename)
Decode file using getName on the File from step 1
Create FileOutputStream from File
Compress the bitmap image into the FileOutputStream
From what I can surmise from your question, it looks as though you're showing a images in a RecyclerView and when an image is clicked, you want to open another activity which shows a version of the full image. If that's close to your use-case, and you're using Glide, I would recommend taking advantage of its built-in automatic caching feature to reduce network calls instead of manually saving the file.
By default, disk and memory-based caching is enabled in Glide as long as the same filename, path, or URL are used to obtain the image on each Glide.load(...). If you'd like to manipulate how the caching occurs, use the DiskCacheStrategy enum to control that every time you load the image:
Glide.with(c)
.load(images.get(position))
.diskCacheStrategy(DiskCacheStrategy.SOURCE) # Will cache the source downloaded image before any transformations are applied
.placeholder(R.mipmap.ic_launcher)
.into(holder.img);
If you still want to save the file for other reasons, use a SimpleTarget instead of loading directly into your ImageView like so:
Glide.with(c)
.load(images.get(position))
.diskCacheStrategy(DiskCacheStrategy.SOURCE) # Will cache the source downloaded image before any transformations are applied
.placeholder(R.mipmap.ic_launcher)
.asBitmap()
.into(new SimpleTarget<GlideDrawable>() {
#Override
public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
holder.img.setImageDrawable(new BitmapDrawable(bitmap));
saveImage(bitmap); # This being an encapsulation of the steps outlined earlier
}
});
I have to share GIF images from URL to some other applications using intent, as per my knowledge for sharing them from url I have to save them first in my phone's memory.
I have used GLIDE lib to show them, how could I store them to share? My code so far (not working): It saves only one image from the set of frames of GIF image.
if (mGIFArrayList != null) {
// imageUri = getLocalBitmapUri(imageViewSimple);
// shareWithAppChooser(imageUri,"");
Glide
.with(mContext)
.load(mGIFArrayList.get(getPosition()).getStrUrl())
.asGif()
.toBytes()
.into(new SimpleTarget<byte[]>() {
#Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
new AsyncTask<Void, Void, Void>() {
#Override protected Void doInBackground(Void... params) {
// File sdcard = Environment.getExternalStorageDirectory();
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "shared_gif_" + System.currentTimeMillis() + ".gif");
File dir = file.getParentFile();
try {
if (!dir.mkdirs() && (!dir.exists() || !dir.isDirectory())) {
throw new IOException("Cannot ensure parent directory for file " + file);
}
BufferedOutputStream s = new BufferedOutputStream(new FileOutputStream(file));
s.write(resource);
s.flush();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
})
;
}
on the following two lines you determine that the drawable is a GlideBitmapDrawable
Drawable drawable = imageView.getDrawable();
if (drawable instanceof GlideBitmapDrawable) {
and then on the following like you cast it to GifDrawable:
GifDrawable gifDrawable = ((GifDrawable) imageView.getDrawable());
I'm sure it's throwing a ClassCastException as GifDrawable and GlideBitmapDrawable are not related.
Unfortunately I don't think you can extract the file from the GifDrawable, because it doesn't work like this.
Probably your best workaround it, is to download the gif file from the link to the device storage, and then sharing the file.
I've just imported the Picasso library in my project and I'm using it like described in this other SO question (I need to download & save some images from web server). The whole thing is working correctly except for a thing: the resulting image in my emulator is bigger (in terms of weight) than the original on server. For example, a JPG image of 52Kb (370 x 505 pixels), result in a JPG image of same resolution (370 x 505) but 132Kb of weight. This is the code I'm using (saw in a lot of SO questions):
if (target == null){
target = new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
File file = new File(getActivity().getFilesDir() + "/saved.jpg");
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream);
ostream.flush();
ostream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
}
Picasso.with(getActivity()).load(sourceValue).into(target);
Thanks you all in advance for your time and your attention.
UPDATE:
Checking the memory of my emulator, I've noticed that the cached version of the image that Picasso create, has the correct size. So, basically, if I use the same code I've posted, but I comment all the try-catch block, the file is just downloaded and cached (not saved in another location) but has the correct size. So it is compression's fault?
In my application the system will download images from an url and save it into phone memory. (I did not included url address in the question) On top of that, it will also save data into sqlite database. Data that save is file name, filepath and file size. But currently once I go through the download process whether the download complete or fail in the middle of the process, it also will insert into the database.
Is there any way that I can check whether the download process is completed or not?
GalleryScreen.this.runOnUiThread(new Runnable() {
#Override
public void run() {
boolean isDownloadResult = false;
int NumIncrease = 0;
Log.i(TAG, "NumberIncrease:" +NumIncrease);
Toast.makeText(getApplicationContext(), "Downloading.............>>>>>>>>>>>", Toast.LENGTH_SHORT).show();
Bitmap bm;
InputStream in;
try{
in = new java.net.URL(URL).openStream();
bm = BitmapFactory.decodeStream(new PatchInputStream(in));
File storage = new File(Environment.getExternalStorageDirectory() + File.separator + "/Images/");
Log.i(TAG,"storage:" +storage);
Log.i(TAG,"storage:" +storage.getAbsolutePath());
if(!storage.exists()){
storage.mkdirs();
}
String FileName = "/"+CONTENT_ID+".jpg";
FileOutputStream fos = new FileOutputStream(storage + FileName);
bm.compress(Bitmap.CompressFormat.JPEG, 85, fos);
String filepath = storage + FileName;
File filecheck = new File (filepath);
long fileSize = filecheck.length();
fos.flush();
fos.close();
Log.i(TAG, "bm:" +bm);
Log.i(TAG, "fos:" +fos);
Log.i(TAG, "filesize:" +fileSize);
Log.i(TAG, "filepath:" +filepath);
helper.insert_content(filepath, fileSize, requestTime);
isDownload = false;
}
catch(IOException e1){
e1.printStackTrace();
}
}
});
Please use AsyncTask. AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)
you can just use an anonymous class for the async task. This would like this:
ImageView mChart = (ImageView) findViewById(R.id.imageview);
String URL = "http://www...anything ...";
mChart.setTag(URL);
new DownloadImageTask.execute(mChart);
The Task class:
public class DownloadImagesTask extends AsyncTask<ImageView, Void, Bitmap> {
ImageView imageView = null;
#Override
protected Bitmap doInBackground(ImageView... imageViews) {
this.imageView = imageViews[0];
return download_Image((String)imageView.getTag());
}
#Override
protected void onPostExecute(Bitmap result) {
imageView.setImageBitmap(result);
}
private Bitmap download_Image(String url) {
...
}
Here, onPostExecute, you can easily check whether the process of download image is completed or not.
Further reading
http://developer.android.com/reference/android/os/AsyncTask.html
Loading Image using AsyncTask
Android : Loading an image from the Web with Asynctask
Android Help with adding a progress dialog while image loading?
EDIT:
If you are trying to download larger files, you might consider
putting your application into some type of Service as this would
potentially take a few hours.
You can consider using Download Manger for newer devices
(with Android 2.3+)
Also a nice resource ->
Download a file with Android, and showing the progress in a ProgressDialog