I have a list of urls for images. I want to use Picasso to download these images to local storage on Android. I am using following method (using custom target). However I don't see all the images getting downloaded.
public void downloadAllMapImages(List<ProjectMapModel> models) {
List<Target> targetList=Lists.newArrayList();
for(ProjectMapModel model:models){
for (Map.Entry<Integer, String> entry : model.getMaps().entrySet()) {
String url=entry.getValue();
Target target=mapImageTarget(model.getProjectId(),entry.getKey());
targetList.add(target);
Picasso.with(this)
.load(url)
.into(target);
}
}
if(!isImageDownloadSuccessful)
showDownloadMapImageDataError();
//whatever images were downloaded, we need to write them to database
listDetailPresenter.onImageDownloadingSuccessful(projectMapOutputModels);
}
private Target mapImageTarget(final int projectId, final int mapType) {
//create the file name
final File file = new File(this.getExternalFilesDir(null) + File.separator + projectId+"_"+ mapType + ".jpg");
final String filePath=file.getAbsolutePath();
return new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
// loading of the bitmap was a success
// write the image to file
new Thread(new Runnable() {
#Override
public void run() {
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
} catch (IOException e) {
Log.e(DashboardActivity.class.getName(), e.toString());
isImageDownloadSuccessful=false;
} finally {
try {
outputStream.close();
Log.i(DashboardActivity.class.getName(), "image saved");
} catch (IOException e) {
Log.e(DashboardActivity.class.getName(), e.toString());
isImageDownloadSuccessful=false;
}
}
projectMapOutputModels.add(new ProjectMapOutputData(projectId,filePath,mapType));
Log.i("image", "image saved to >>>" + filePath);
}
}).start();
//notify presenter that this image has been download and the path can be sent to presenter
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
// loading of the bitmap failed
// TODO show error message toast. dont write file path to database. continue with next image
isImageDownloadSuccessful=false;
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
}
Am I missing anything? Any help on this is really appreciated!
Related
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.
}
}
}
I am trying to download and save all the images from a url array but the problem is only last image gets saved with the name img7.jpg. I don't understand where the problem is? I want all the images to be downloaded and saved with the name img1.jpg, img2.jpg, img3.jpg and so on. Where in the code do I need to make changes?
public class MainActivity extends ActionBarActivity {
ImageView imageView;
public static String[] stringArray = {"http://upload.wikimedia.org/wikipedia/en/9/90/Broken_Boundaries_of_Rohtas_Fort.jpg",
"http://upload.wikimedia.org/wikipedia/en/a/a0/Rohtas_View_4.jpg",
"http://upload.wikimedia.org/wikipedia/en/0/07/Rohtas_Fort_Gate.jpg",
"http://upload.wikimedia.org/wikipedia/en/7/78/Rohtas_Village_View_2nd.jpg",
"http://www.worldheritagesite.org/picx/w586.jpg",
"http://wpcontent.answcdn.com/wikipedia/en/thumb/6/68/Rani_Mahal_Rohtas_Fort_2.jpg/930px-Rani_Mahal_Rohtas_Fort_2.jpg",
"http://photos.wikimapia.org/p/00/01/75/75/69_big.jpg"};
int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView)findViewById(R.id.imageView1);
for (String url : stringArray){
Picasso.with(this)
.load(url)
.into(target);
i++;
}
}
private Target 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(Environment.getExternalStorageDirectory().getPath() +"/img"+i+".jpg");
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 75, ostream);
ostream.close();
}
catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
if (placeHolderDrawable != null) {
}
}
};
}
In your case Picasso loads your images asynchronously. What means, that
Picasso.with(this)
.load(url)
.into(target);
isn't waiting until your picture is downloaded and stored to disk. So, your counter i is always (stringArray.length - 1), if it comes to saving the image.
Do something like this:
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int index = 0;
for (String url : stringArray) {
Picasso.with(this)
.load(url)
.into(new IndexTarget(index));
index++;
}
}
class IndexTarget implements Target {
private final int mIndex;
public IndexTarget(int index){
this.mIndex = index;
}
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
File file = new File(Environment.getExternalStorageDirectory().getPath() +"/img"+mIndex+".jpg");
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, ostream);
ostream.close();
}
catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
}
I'm trying to show my news in a custom ListView. Each news is included of some images and I want to
1.download images from server
2.save in local storage
3.save path of images into SQLite
4.show images in ListView using my custom adapter.
I just have problem with steps 1 & 2. I can get news from server and show them in my ListView
and show images from cache by add below code in my adapter:
Picasso.with(context).load(image[position]).into(iv);
By using Picasso.with(context).load(image[position]).into(target) , just I can save one
image in storage.
Please suggest me your idea ...
UPDATE: When I use below code, just one image (last index of my image array) being saved!
How can I save all images in array with this code?!
#Override
protected void onPostExecute(Void result) {
SaveImages();
pDialog.dismiss();
super.onPostExecute(result);
}
String fileName = null;
public void SaveImages() {
for(int i = 0; i < image.length; i++) {
Picasso.with(this).load(image[i]).into(target);
fileName = "image-" + i + ".jpg";
}
}
Target target = new Target() {
#Override
public void onPrepareLoad(Drawable arg0) {
}
#Override
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom arg1) {
File file = new File(Environment.getExternalStorageDirectory().getPath() +"/" + fileName);
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 75, ostream);
ostream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onBitmapFailed(Drawable arg0) {
}
};
Try to put Target target definition before call to Picasso.with(this).load(image[i]).into(target);
P.S. Using the following code and I saved images very well. Thanks, anyway.
My Code:
final String fileName = mDataset.get(i).getAid() + ".jpg";
Target target = new Target() {
#Override
public void onPrepareLoad(Drawable arg0) {
return;
}
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom arg1) {
try {
File file = null;
// judge "imgs/.nomedia"'s existance to judge whether path available
if(LightCache.testFileExist(GlobalConfig.getFirstStoragePath()
+ "imgs" + File.separator +".nomedia") == true)
file = new File(GlobalConfig.getFirstStoragePath()
+ "imgs" + File.separator + fileName);
else file = new File(GlobalConfig.getSecondStoragePath()
+ "imgs" + File.separator + fileName);
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
ostream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onBitmapFailed(Drawable arg0) {
return;
}
};
Picasso.with(GlobalConfig.getContext())
.load(Wenku8API.getCoverURL(mDataset.get(i).getAid()))
.into(target);
Custom target for storing photo in phone gallery.
public class TargetPhoneGallery implements Target
{
private final WeakReference<ContentResolver> resolver;
private final String name;
private final String desc;
public TargetPhoneGallery(ContentResolver r, String name, String desc)
{
this.resolver = new WeakReference<ContentResolver>(r);
this.name = name;
this.desc = desc;
}
#Override
public void onPrepareLoad (Drawable arg0)
{
}
#Override
public void onBitmapLoaded (Bitmap bitmap, LoadedFrom arg1)
{
ContentResolver r = resolver.get();
if (r != null)
{
MediaStore.Images.Media.insertImage(r, bitmap, name, desc);
}
}
#Override
public void onBitmapFailed (Drawable arg0)
{
}
}
Picasso.with(context).load(image[position]).into(new TargetPhoneGallery(view.getContentResolver(), "image name", "image desc"));
although this post is old, it seems the question hasn't been answered yet.
Reading your code, it appears the call you make to picasso could be asynchronous.
You should definitely check that, as if it is the case, you are starting image.length tasks, changing the filename at each new task, leading all tasks to complete and save to the last filename that was set.
To solve this, you should override Target constructor and add a filename parameter so it's ready when the task ends, in your onBitmapLoaded listener.
I'm currently downloading and save some pictures in my Android app.
Here is the class which do the work :
public class BitmapPersist extends AsyncTask<String, Void, Boolean> {
private ArrayList<String> photosNotDownloaded;
private File pointDir;
private KickstartrGeolocPoint point;
private OnBitmapPersistedListener onBitmapPersistedListener;
public BitmapPersist(ArrayList<String> photosNotDownloaded, File pointDir, KickstartrGeolocPoint point, OnBitmapPersistedListener onBitmapPersistedListener) {
this.photosNotDownloaded=photosNotDownloaded;
this.pointDir=pointDir;
this.point=point;
this.onBitmapPersistedListener=onBitmapPersistedListener;
}
#Override
protected Boolean doInBackground(String... params) {
Bitmap bmp;
FileOutputStream out = null;
for(String url : photosNotDownloaded) {
//download the picture synchronously
bmp = ImageLoader.getInstance().loadImageSync(url);
try {
out = new FileOutputStream(pointDir.getPath() + File.separator + FileUtils.getPointPhotoPrefix(point) + FileUtils.getFileNameFromUrl(url));
bmp.compress(Bitmap.CompressFormat.JPEG, 90, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (Throwable ignore) {
}
}
//send notification to the UI in order to scan again the directory and update the carousel
publishProgress();
}
return true;
}
#Override
protected void onPostExecute(Boolean success) {
if (success)
onBitmapPersistedListener.persistedSuccessfully(this.point, this.pointDir);
else
onBitmapPersistedListener.errorInPersistance();
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
onBitmapPersistedListener.onProgress();
}
}
This class take an ArrayList of urls in parameter, and for each photo, it download it and save it.
Each time a photo is persisted, a notification is sent to the view to update a carousel (thanks to publishProgress(); )
The problem is that publishProgress() does not work, and every photos are displayed at the same time when every photos are downloaded.
Here is the call of my asynctask :
private void persistImageforPoint(ArrayList<String> photosNotDownloaded, KickstartrGeolocPoint point, File pointDir) {
// Create a subfolder for each point with its id
if (!pointDir.exists()) {
if (!pointDir.mkdirs()) {
LogWrapper.debug(FileUtils.class, "Failed to create directory");
return;
}
}
//save the file. Asynchronous task --> do not block the UI
new BitmapPersist(photosNotDownloaded, pointDir, point, new OnBitmapPersistedListener() {
#Override
public void persistedSuccessfully(KickstartrGeolocPoint point, File pointDir) {
if(currentPoint!=null) {
File pointDirectory = FileUtils.getPointPhotoDir(getActivity(), currentPoint);
loadCarousel(currentPoint, pointDirectory);
}
}
#Override
public void errorInPersistance() {
LogWrapper.error(getClass(),"Error persisting image");
}
#Override
public void onProgress() {
if(currentPoint!=null) {
final File pointDir = FileUtils.getPointPhotoDir(getActivity(), currentPoint);
loadCarousel(currentPoint, pointDir);
}
}
}).execute();
}
I don't have any errors in my logcat.
Thanks for your help ;)
I'm trying to modify koush's code from download sample with progressbar, to make it write to a FileOutputStream instead of File, but eclipse give me the following error:
The method progressHandler(new ProgressCallback(){}) is undefined for
the type ResponseFuture
Here is the code:
File file = new File(DownloadPath, uri.getLastPathSegment());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
}
Future<FileOutputStream> downloading = Ion.with(getApplicationContext())
.load(uri)
.write(fos)
.progressHandler(new ProgressCallback() {
#Override
public void onProgress(int downloaded, int total) {
// inform the progress bar of updates in progress
}
})
.setCallback(new FutureCallback<FileOutputStream>() {
#Override
public void onCompleted(Exception e, FileOutputStream file) {
// download done...
// do stuff with the File or error
}
});
You seem to have messed up with the order. Please try this:
Future<FileOutputStream> downloading = Ion.with(getApplicationContext())
.load("http://example.com/test.txt")
.progressHandler(new ProgressCallback() {
#Override
public void onProgress(int downloaded, int total) {
// inform the progress bar of updates in progress
}
})
.write(fos)
.setCallback(new FutureCallback<FileOutputStream>() {
#Override
public void onCompleted(Exception e, FileOutputStream file) {
// download done...
// do stuff with the File or error
}
});