In the project universal image loader was used for displaying gridview,viewpager.while I need to integrate the offline mode for app,
I need to download and store images on disc in separate thread and then when displaying gridview ,viewpager images should load from disc.
How to implement universal-image-loader in separate thread? I have tried it but after some time the activity exits it's like the thread and loading universal imageloader exceeds the app cache,I mean somethings goes wrong. I have seen different discussions but I really need to download via UIL in separate thread.
#Override
public void run() {
int x = 0;
while (x < 1) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
processBitmaps();
}
}
public void processBitmaps() {
fulls = Application.getOnThisDeviceFulls();
if (fulls != null && fulls.size() > 0) {
for (int index = 0; index < fulls.size(); index++) {
Full full= fulls.get(index).getFull();
ArrayList<Page> pages =fulls.get(index).getPages();
for (int j = 0; j < pages.size(); j++) {
String pagePattern = ...
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
loadUILImage();
if (j == pages.size() - 1) {
Application.removeFullOnDevice(index);
}
if (resetIndex) {
break;
}
}
if (resetMagazineIndex) {
magazineIndex = 0;
Log.i("magazinethread ", resetIndex + "");
resetIndex = false;
break;
}
}
}
}
The simple example in the documentation works thread based:
// Load image, decode it to Bitmap and return Bitmap to callback
imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
// Do whatever you want with Bitmap
}
});
Use the ImageLoaderConfiguration in order to define particular threading parameters:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.threadPoolSize(3)
.threadPriority(Thread.NORM_PRIORITY - 2)
...
From the JavaDoc:
public void loadImage(String uri, ImageLoadingListener listener)
Adds load image task to execution pool. Image will be returned with
ImageLoadingListener.onLoadingComplete(String, android.view.View,
android.graphics.Bitmap) callback}. NOTE:
init(ImageLoaderConfiguration) method must be called before this
method call
Related
I have a requirement where I want to make multiple GET requests, what will be best practice in java not using RxJava.
Here I have given parameter as i in getPhotos(), specifies id which loads data in json accordingly. This can run concurrently.
PhotoList list = UnplashClient.getUnplashClient().create(PhotoList.class);
for(int i=0; i<10; i++) {
call = list.getPhotos(i);
call.enqueue(new Callback<List<Photo>>() {
#Override
public void onResponse(Call<List<Photo>> call, Response<List<Photo>> response) {
}
#Override
public void onFailure(Call<List<Photo>> call, Throwable t) {
}
});
If you are looking for serial execution of api calls one after the other, you can make use of Task. This is similar to what Rx java is doing.
Please find the pseudo code below with an example :
private void fetchPhotos() {
Task<Photo> task = null;
List<Photo> photos = new ArrayList<>();
for (int i = 0; i < 10; i++) {
if (task == null) {
task = getPhoto(i);
} else {
final int pos = i;
task = task.onSuccessTask(photo -> {
photos.add(photo);
return getPhoto(pos);
});
}
}
task.addOnCompleteListener((photoTask) -> {
photos.add(photoTask.getResult()); //Adding the final result.
for (int i = 0; i < photos.size(); i++) {
Log.i("DEMO", photos.get(i).toString());
}
});
}
private Task<Photo> getPhoto(int i) {
Task<Photo> task = Tasks.call(Executors.newSingleThreadExecutor() /*You can specify the threading here*/, () -> new Photo(i) /*Your logic to fetch photo goes here...*/);
return task;
}
class Photo {
int pos = 0;
Photo(int p) {
this.pos = p;
}
#Override
public String toString() {
return String.valueOf(pos);
}
}
Running above code, you can see result in sequential order printed in Logcat. Here the chaining of requests happens from the success of previous request.
I'm solving my problem about Image Loader and I have some problems..
What I want is to show many images (about 400) in GridView(or ListView).
I don't want to use the Library like Picasso, Glide like that.
and Here is the problem.
When I call the method which convert from url to bitmap?
3.1. before setAdapter, then pass the bitmap array.
3.2. while getView.
two things are working well. but too much slow... maybe cuz of the times to call URLConnection..
Could anyone help me about these problem? How can I speed up? or are there any other solution without Open Source.
Here is my Source.
Now, 3-1.
ShowImage
private void showImages(ArrayList<String> imgUrls) {
ArrayList<Bitmap> bitmaps = new ArrayList<>();
for (int i = 0; i < imgUrls.size(); i++) {
try {
String img_path = imgUrls.get(i);
Bitmap bitmap = new UriToBitmapAsyncTask().execute(img_path).get();
bitmaps.add(bitmap);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
CustomAdapter adapter = new CustomAdapter(getApplicationContext(),R.layout.row,bitmaps);
gridView.setAdapter(adapter);
}
and This is the customAdapter's GetView
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflator.inflate(rowLayout, parent, false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.imageView.setImageBitmap(bitmaps.get(position));
return convertView;
}
You should really take Reinventing the wheel to heart but if you really want to toture yourself an Approach could be:
use a ThreadPoolExecutor to fetch more images at once, you should read up how to use them
implement a way to cancel threads who load a img for a griditem which isn't displayed anymore
use two sets of data a thumbnail which loads faster for the grid view and a real image which gets loaded when the user clicks on the grid
dont't forget to use a LRU caching method or your device will run out of memory depending on the images
Don't use ArrayList to store bitmaps. Bitmaps usually take consumes a lot of memory. Try using LRUCache like this way,
public class TCImageLoader implements ComponentCallbacks2 {
private TCLruCache cache;
public TCImageLoader(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
int maxKb = am.getMemoryClass() * 1024;
int limitKb = maxKb / 8; // 1/8th of total ram
cache = new TCLruCache(limitKb);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class TCLruCache extends LruCache<String, Bitmap> {
public TCLruCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(ImagePoolKey key, Bitmap value) {
int kbOfBitmap = value.getByteCount() / 1024;
return kbOfBitmap;
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
#Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
}
else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 1;
}
#Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
}
#Override
public void onLowMemory() {
}
#Override
public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}
}
get a instance of TCImageLoader and call display method appropriately.
I want to get a Bitmap[] from my String[] with links. But this doesn't work as I want. I have this Method:
private Bitmap[] getBitmaps(String[] images){
ArrayList<Bitmap> temp = new ArrayList<>();
for(int i = 0; i < images.length; i++){
ImageView img = new ImageView(getContext());
FrameLayout.LayoutParams x = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
img.setLayoutParams(x);
Picasso.with(getContext()).load(MainPostAdapter.USER_URL+images[i]+".png").into(img, new Callback() {
#Override
public void onSuccess() {
temp.add(BitmapRes.drawableToBitmap(img.getDrawable()));
movableBackgroundContainer.removeView(img);
}
#Override
public void onError() {
}
});
movableBackgroundContainer.addView(img);
}
return temp.toArray(new Bitmap[temp.size()]);
}
The problem is I get a null Array because it adds the Bitmap to the list after the onSuccess function. How can I now wait until all onSuccess added the bitmaps and then return?
The get() function of Picasso does what you're looking for. It downloads a Bitmap rather than load an image into an ImageView. Note that Picasso's get() method cannot be called on the main thread. My example uses an AsyncTask to download images on a separate thread.
String[] images = new String[] {"http://path.to.image1.jpg", "http://path.to.image2.jpg"};
new AsyncTask<String[], Void, List<Bitmap>>() {
#Override
protected List<Bitmap> doInBackground(String[]... params) {
try {
List<Bitmap> bitmaps = new ArrayList<Bitmap>();
for (int i = 0; i < params[0].length; ++i) {
bitmaps.add(Picasso.with(getActivity()).load(params[0][i]).get());
}
return bitmaps;
} catch (IOException e) {
return null;
}
}
#Override
public void onPostExecute(List<Bitmap> bitmaps) {
if (bitmaps != null) {
// Do stuff with your loaded bitmaps
}
}
}.execute(images);
You could increase an integer every time on success until the integer equals to the images.lengh(). You could check this with a loop. And in the loop is an if clause within the return.
For example
int currentSuccess = 0;
In the loop:
#Override
public void onSuccess() {
temp.add(BitmapRes.drawableToBitmap(img.getDrawable()));
movableBackgroundContainer.removeView(img);
currentSuccess++;
}
And for the return:
while(true){
if(currentSuccess == images.length){
return temp.toArray(new Bitmap[temp.size()]);
}
}
Hope that helps.
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);
what i have is a grid view and i open the images online . but what i need to do is when the user open the app .. all of those images to be downloaded in the mobile phone automatically so when the user open the app again it will show up from the memory not online ..
please any help?? and what i have is 250 images maybe
and is there any other so i can call my images dynamically instead of calling them one by one??
here is an example of how i call my images:
private String urls[] = {
"http://transition-se.com/training_may/foodribbons.JPG",
"http://transition-se.com/training_may/clothribbon.JPG",
"http://transition-se.com/training_may/shoesribbon.JPG",
"http://transition-se.com/training_may/bagsribbon.JPG",
"http://transition-se.com/training_may/viewsribbon.JPG",
"http://transition-se.com/training_may/makeupribbon.JPG",
"http://transition-se.com/training_may/roomribbon.JPG",
"http://transition-se.com/training_may/watchesribbon.JPG"
};
You can do it like a hard way, or you can do it easy way.
You can make symple Asynk task and load images to files on your device.
Example:
private class Downloader extends AsyncTask<String, Void, Integer> {
#Override
protected void onPreExecute() {
// show dialog loading here
}
#Override
protected Integer doInBackground(String... params) {
// for loop here
for(int i=0; i<params.lenght; i++) {
try {
URL url = new URL(params[i]);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream( file name here );
// add this file to global list, so you can used it after
byte[] b = new byte[1024];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
return 1;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
#Override
protected void onProgressUpdate(Void... values) {
// update loading dialog precents
}
#Override
protected void onPostExecute(Integer result) {
// hide loading dialog
if (result == 1) {
// all images loaded to files
}
}
}
Or you can use out of the box libs for this operation which i prefer, try this Picasso Asynk image loader, it will handle complex operation for you
Handling ImageView recycling and download cancelation in an adapter.
Complex image transformations with minimal memory use.
Automatic memory and disk caching.