Android Expansion File to Custom Picasso Downloader - InputStream - android

I’m working on this code where I populate the city picture using Picasso and getting it from expansion file. Then, I followed the instructions here and here.
No one worked for me. The code bellow and few more details follows:
final ExpansionFileLoader expansionFileLoader = new ExpansionFileLoader(this, App.Constants.EXPANSION_FILE_VERSION_NUMBER);
Picasso picasso = new Picasso.Builder(this)
.downloader(new Downloader() {
#Override
public Response load(Uri uri, int networkPolicy) throws IOException {
Log.d("CityActivity", "loading the image file of the chosen city");
InputStream inputStream = expansionFileLoader.getInputStream(uri.toString());
return new Response(inputStream, false, -1);
}
#Override
public void shutdown() {
}
})
.build();
picasso.load(Uri.parse(App.ViewData.selectedCity.image_file_path)).into(PicassoTools.setBackgroundTarget(findViewById(R.id.navigation_drawer_layout)));
I have put breakpoints in the downloader and the main reason is because load is not being called for some reason. So probably Im doing some basic mistake when creating the downloader or Picasso builder.
Btw, I'm using Picasso 2.5.
That is my target settings(which is just a detail, and won't matter for the load method to be called):
public static Target setBackgroundTarget(View view) {
return setBackgroundTarget(view, null);
}
public static Target setBackgroundTarget(View view, Runnable callback) {
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
int sdk = android.os.Build.VERSION.SDK_INT;
if (sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
view.setBackgroundDrawable(new BitmapDrawable(App.context.getResources(), bitmap));
} else {
view.setBackground(new BitmapDrawable(App.context.getResources(), bitmap));
}
if (callback != null) callback.run();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.e("PICASSO", "Bitmap Failed");
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
// use placeholder drawable if desired
Log.d("PICASSO", "Bitmap Preload");
}
};
view.setTag(target);
return target;
}
Let me know any other detail you wanna know. Thanks a lot for the help.
Cheers

Related

Downloading Image via Picasso sometimes fails

I am using Picasso to download images from the web but sometimes it works and sometimes it fails. It's very irritating and I can't find a way to fix this. Any help?
My code to download image:
public void imageDownload(Context ctx, String url){
Picasso.with(ctx)
.load(spp)
.into(getTarget(url));
}
//Using the Picasso Target Class
private Target getTarget(String url){
final String temp = url;
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() + "/" + temp);
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
ostream.flush();
ostream.close();
} catch (IOException e) {
Log.e("IOException", e.getLocalizedMessage());
}
}
}).start();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
return target;
}
I call this method as:
imageDownload(getActivity(),"image.jpg");
from documentation of method into(Target t):
Note: This method keeps a weak reference to the {#link Target}
instance and will be garbage collected if you do not keep a
strong reference to it. To receive callbacks when an image is
loaded use {#link #into(android.widget.ImageView, Callback)}
You don't keep a reference to the instance of Target you have created so it can be collected by garbage collector as documentation states. This can explain random behavior you observed.
One solution is suggested in the documentation ( use into(android.widget.ImageView, Callback)).
Another solution is to keep a reference to an instance of Target.
target = getTarget(url); //declared as a field of a class
Picasso.with(ctx)
.load(spp)
.into(target);

Android - How to download images from s3?

I'm reading the s3 android guide and im really confused on how to download my files.
They provide this code:
TransferObserver observer = transferUtility.download(
MY_BUCKET, /* The bucket to download from */
OBJECT_KEY, /* The key for the object to download */
MY_FILE /* The file to download the object to */
);
So what is MY_FILE? am i suppose to make a local empty file object and supply it into that transferUtility download function and it fills that empty file to the one download?
And, when i finish getting the file, (particularly for images) how do i upload that file into an imageView using glide or Picasso?
I am not sure how to use the TransferObserver object.
Hope someone can provide a working example, please!
cheers!
Although I am quite late answering this question. Hope this helps someone who is stuck in this problem.
You don't need to make the bucket public. You can directly show the image via Glide. Here is my repo to load image from amazon s3 bucket via Glide.
https://github.com/jontyankit/Glide-Amazon-Image-Load
You need to override GlideModule and register our component
public class CustomGlideModule implements GlideModule {
#Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}
#Override
public void registerComponents(Context context, Glide glide) {
glide.register(ImageModel.class, InputStream.class, new ImageLoader.Factory());
}
}
Make custom ModelLoader class. This class fetches the image on the basis of model described above instead of URL
public class ImageLoader implements ModelLoader<ImageModel, InputStream> {
private final ModelCache<ImageModel, ImageModel> mModelCache;
public ImageLoader(ModelCache<ImageModel, ImageModel> mModelCache) {
this.mModelCache = mModelCache;
}
#Override
public DataFetcher<InputStream> getResourceFetcher(ImageModel model, int width, int height) {
ImageModel imageModel = model;
if (mModelCache != null) {
imageModel = mModelCache.get(model, 0, 0);
if (imageModel == null) {
mModelCache.put(model, 0, 0, model);
imageModel = model;
}
}
return new ImageFetcher(imageModel);
}
public static class Factory implements ModelLoaderFactory<ImageModel, InputStream> {
private final ModelCache<ImageModel, ImageModel> mModelCache = new ModelCache<>(500);
#Override
public ModelLoader<ImageModel, InputStream> build(Context context, GenericLoaderFactory factories) {
return new ImageLoader(mModelCache);
}
#Override
public void teardown() {
}
}
}
And at last make custom class DataFetcher. public InputStream loadData(Priority priority) is the method which will download image from Amazon.
public class ImageFetcher implements DataFetcher<InputStream> {
private final ImageModel imageModel;
private InputStream mInputStream;
boolean downloadComplete = false;
int transferId = 0;
public ImageFetcher(ImageModel imageModel) {
this.imageModel = imageModel;
}
#Override
public InputStream loadData(Priority priority) throws Exception {
return fetchStream(imageModel);
}
private InputStream fetchStream(final ImageModel imageModel) {
TransferUtility transferUtility = AmazonClient.getClient().getTransferUtility();
TransferObserver bolomessages = transferUtility.download(imageModel.getBucketName(), imageModel.getId(), new File(imageModel.getLocalPath()));
transferId = bolomessages.getId();
bolomessages.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
Log.wtf("AWSS3", "onStateChanged = " + state);
if (state == TransferState.COMPLETED) {
File initialFile = new File(imageModel.getLocalPath());
try {
mInputStream = new FileInputStream(initialFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
downloadComplete = true;
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
}
#Override
public void onError(int id, Exception ex) {
// do something
Log.wtf("AWSS3", "onError");
ex.printStackTrace();
downloadComplete = true;
}
});
while (!downloadComplete){}
return mInputStream;
}
#Override
public void cleanup() {
if (mInputStream != null) {
try {
mInputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
mInputStream = null;
}
}
}
#Override
public String getId() {
return imageModel.getId();
}
#Override
public void cancel() {
AmazonClient.getClient().getTransferUtility().cancel(transferId);
}
}
So I am able to use Glide or picasso to load the image using the url of the image in the s3 bucket. But you have to make the bucket public.
Here is how you upload the image:
Glide.with(getActivity().getBaseContext()).load("IMAGE URL FROM S3").centerCrop().into(cardImage);
And thanks to #KNeerajLal here is how you can make your bucket public.
Here:
making bucket public

Picasso Targets onBitmapLoaded not called in for loop

Below code snippet for load file into Bitmap and save this file in internal directory(i.e PNG,or JPG format)
final List<Target> targets = new ArrayList<Target>();
final List<Target> targetsNormal = new ArrayList<Target>();
for (int j = 0; j < defaultTileImage.size(); j++) {
final String slangTiles = defaultTileImage.get(j).getPairName() +
ApplicationConstants.SLANG_TILES;
final String normalTiles = defaultTileImage.get(j).getPairName() +
ApplicationConstants.NORMAL_TILES;
final int k = j;
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i("Targets", "Loaded: " + k);
targets.remove(this);
saveIntoBitmap(bitmap, slangTiles);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
targets.remove(this);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.i("Targets", "Preparing: " + k);
}
};
Target targetNormal = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i("TargetsNormal", "Loaded: " + k);
targetsNormal.remove(this);
saveIntoBitmapSlang(bitmap, normalTiles);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
targetsNormal.remove(this);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.i("TargetsNormal", "Preparing: " + k);
}
};
targetsNormal.add(targetNormal);
Picasso.with(MainActivity.this)
.load(defaultTileImage.get(j).getNormalTileImg()) // Start loading the current target
.resize(100, 100)
.into(targetNormal);
targets.add(target);
Picasso.with(MainActivity.this)
.load(defaultTileImage.get(j).getSlangTileImg()) // Start loading the current target
.resize(100, 100)
.into(target);
}
Also visited this link and implemented as per this guideline that make Target a strong reference . But unfortunately many time onBitmapLoaded not get any callback.
I truly appreciate your help in resolving the problem
Make sure targets and targetsNormal are global variables instead of local.
If they are local variables, they can be garbage collected as soon as the method has been left.

Saving image from URL using Picasso without change in size (using bitmap.compress() changes size)

I am using Picasso for my image handling and use it to download images from a backend server and save to the local device. I use Target to save the image
Picasso.with(context)
.load(url)
.into(target);
Since the target code gets a bitmap, I have to use bitmap.compress() to write the image to local disk and I use JPEF format with quality of 100 assuming this will preserve the original quality.
Reading this it seems like this might not be what I want. In one case, the image on the backend was 90kb and the image that was written was 370kb. The original image can be generated using an arbitrary quality value. What is the easiest way to save the image using Picasso without the size/quality changing?
Target target = new Target() {
#Override
public void onPrepareLoad(Drawable arg0) {
}
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom arg1) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
FileOutputStream out = null;
try {
out = new FileOutputStream(imagePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void onPostExecute(Void info) {
}
}.execute();
}
#Override
public void onBitmapFailed(Drawable arg0) {
}
};
UPDATE: more elegant solution here: https://github.com/square/picasso/issues/1025#issuecomment-102661647
Solved the problem using this solution.
In my PagerAdapter's instantiateItem() method, I run an AsyncTask that will download the image, save it to a file and then call Picasso with that image file.
PagerAdapter instantiateItem():
RemoteImageToImageViewAsyncTask remoteImageToImageViewAsyncTask =
new RemoteImageToImageViewAsyncTask(imageView, url, imagePath);
remoteImageToImageViewAsyncTask.execute();
RemoteImageToImageViewAsyncTask
public class RemoteImageToImageViewAsyncTask extends AsyncTask<Void, Void, Void> {
ImageView imageView;
String url;
File output;
public RemoteImageToImageViewAsyncTask(ImageView imageView, String url, File output) {
this.imageView = imageView;
this.url = url;
this.output = output;
}
#Override
protected Void doInBackground(Void... params) {
// Downloads the image from url to output
ImageDownloader.download(url, output);
return null;
}
#Override
protected void onPostExecute(Void params) {
Picasso.with(context)
.load(output)
.into(imageView);
}
}

How to set Bitmap on ImageView using library Volley

I'm trying to use the library to perform volley download images from my server.
In my activity I add items dynamically and then realize the exchange of image at runtime.
Below is the code of the attempt to get the picture:
public void updateThumbnails(ArrayList<Book> arrBook,ArrayList<View> arrView){
if(arrBook.size()<= 0){
return;
}
if(arrView.size() <= 0){
return;
}
int intBooks = arrView.size();
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
for(int intIndex = 0; intIndex < intBooks; intIndex++){
View _view = arrView.get(intIndex);
final View _viewLoader = _view;
imageLoader.get(Const.START_REQUEST_BOOK_IMAGE + arrBook.get(intIndex).getId().toString() + ".jpg", new ImageLoader.ImageListener() {
#Override
public void onResponse(ImageLoader.ImageContainer imageContainer, boolean b) {
ImageView imgBook = (ImageView) _viewLoader.findViewById(R.id.img_book);
animationChangeImage(imageContainer.getBitmap(),imgBook);
}
#Override
public void onErrorResponse(VolleyError volleyError) {
}
});
TextView txtTitleBook = (TextView) _view.findViewById(R.id.name_book);
txtTitleBook.setVisibility(View.INVISIBLE);
}
}
You need to check that the returned bitmap (imageContainer.getBitmap()) isn't null before going ahead and assigning it.
Try and adding log prints to see if you're getting errors or a null bitmap, which could mean you're performing a bad request or server error, or perhaps the fault is in the animationChangeImage method if the bitmap is received successfully.
Did you try using the ImageRequest class? For example:
ImageRequest irq = new ImageRequest(imgUrl, new Response.Listener<Bitmap>() {
#Override
public void onResponse(Bitmap response) {
imView.setImageBitmap(response);
}
}, 0, 0, null, null);

Categories

Resources