mirror of
https://github.com/pierre42100/ComunicAndroid
synced 2024-12-27 22:18:58 +00:00
New version of ImageLoad more efficient
This commit is contained in:
parent
3a54768224
commit
a1d791b232
@ -0,0 +1,71 @@
|
||||
package org.communiquons.android.comunic.client.data.ImageLoad;
|
||||
|
||||
import org.communiquons.android.comunic.client.data.Utilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Download an image and save it into a file
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
* Created by pierre on 11/18/17.
|
||||
*/
|
||||
|
||||
class ImageDownloadRunnable implements Runnable {
|
||||
|
||||
private String url;
|
||||
private File dest;
|
||||
|
||||
/**
|
||||
* Instantiate the class for a specific image
|
||||
*
|
||||
* @param url The URL were the image can be retrieved
|
||||
* @param dest The destination file to the image
|
||||
*/
|
||||
ImageDownloadRunnable(String url, File dest){
|
||||
this.url = url;
|
||||
this.dest = dest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform the download
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
//Open the file for writing
|
||||
if(!dest.createNewFile())
|
||||
return;
|
||||
OutputStream os = new FileOutputStream(dest, false);
|
||||
|
||||
//Open the connection
|
||||
URL urlObj = new URL(url);
|
||||
HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
|
||||
|
||||
conn.setDoInput(true);
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(5000);
|
||||
|
||||
conn.connect();
|
||||
|
||||
//Get input stream
|
||||
InputStream is = conn.getInputStream();
|
||||
|
||||
//Transfer bytes
|
||||
Utilities.InputToOutputStream(is, os);
|
||||
|
||||
os.close();
|
||||
is.close();
|
||||
conn.disconnect();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package org.communiquons.android.comunic.client.data.ImageLoad;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* This runnable apply a bitmap on an image view.
|
||||
*
|
||||
* This runnable is intended to be run on the UI thread
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
* Created by pierre on 11/18/17.
|
||||
*/
|
||||
class ImageLoadApplyRunnable implements Runnable {
|
||||
|
||||
/**
|
||||
* The bitmap to appply
|
||||
*/
|
||||
private Bitmap bitmap;
|
||||
|
||||
/**
|
||||
* The target image view
|
||||
*/
|
||||
private ImageView imageView;
|
||||
|
||||
/**
|
||||
* Construct the class
|
||||
*
|
||||
* @param imageView The target image view
|
||||
* @param bitmap The bitmap to apply
|
||||
*/
|
||||
ImageLoadApplyRunnable(ImageView imageView, Bitmap bitmap){
|
||||
|
||||
//Save the values
|
||||
this.bitmap = bitmap;
|
||||
this.imageView = imageView;
|
||||
}
|
||||
|
||||
/**
|
||||
* This operation should be run only on the UI Thread
|
||||
*/
|
||||
@Override
|
||||
@UiThread
|
||||
public void run() {
|
||||
|
||||
//Apply the image
|
||||
imageView.setImageBitmap(bitmap);
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package org.communiquons.android.comunic.client.data.ImageLoad;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* Image load manager
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
* Created by pierre on 11/18/17.
|
||||
*/
|
||||
|
||||
public class ImageLoadManager {
|
||||
|
||||
/**
|
||||
* The list of running operations
|
||||
*/
|
||||
private static ArrayMap<View, Thread> threads = null;
|
||||
|
||||
/**
|
||||
* Private constructor
|
||||
*/
|
||||
private static void construct(){
|
||||
|
||||
//Initializate threads list
|
||||
threads = new ArrayMap<>();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check wether the class has been already initialized or not
|
||||
*
|
||||
* @return True if the class is already initialized
|
||||
*/
|
||||
private static boolean is_constructed(){
|
||||
return threads != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new operation
|
||||
*
|
||||
* @param context The context of the application
|
||||
* @param url The URL of the image to load
|
||||
* @param imageView The target view for the image
|
||||
*/
|
||||
public static void load(Context context, String url, ImageView imageView){
|
||||
|
||||
//Initializate class if required
|
||||
if(!is_constructed())
|
||||
construct();
|
||||
|
||||
//Remove any previously existing operation
|
||||
remove(imageView);
|
||||
|
||||
//Create the new thread
|
||||
Thread thread = new Thread(new ImageLoadRunnable(context, imageView, url));
|
||||
threads.put(imageView, thread);
|
||||
|
||||
//Run it
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove (and kill) a thread associated to a view
|
||||
*
|
||||
* @param view The target view
|
||||
*/
|
||||
public static void remove(ImageView view){
|
||||
|
||||
//Check if the view has an associated thread
|
||||
if(threads.containsKey(view)){
|
||||
|
||||
Thread thread = threads.get(view);
|
||||
|
||||
//Kill the thread if it is alive
|
||||
if(thread != null){
|
||||
if(thread.isAlive())
|
||||
thread.interrupt();
|
||||
}
|
||||
|
||||
//Remove the thread from the list
|
||||
threads.remove(view);
|
||||
|
||||
}
|
||||
|
||||
//Clean the list
|
||||
clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the list of pending operations
|
||||
*/
|
||||
private static void clean(){
|
||||
|
||||
//Get the list of threads
|
||||
for(View view : threads.keySet()){
|
||||
|
||||
if(threads.get(view) != null)
|
||||
//Check if the associated thread with the view is still alive or not
|
||||
if(!threads.get(view).isAlive())
|
||||
threads.remove(view);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
package org.communiquons.android.comunic.client.data.ImageLoad;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
* Image loading runnable
|
||||
*
|
||||
* The advantages of this manager are the following for image loading : it avoid a single file to be
|
||||
* downloaded several times and it several images to be downloaded at once
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
* Created by pierre on 11/18/17.
|
||||
*/
|
||||
|
||||
class ImageLoadRunnable implements Runnable {
|
||||
|
||||
/**
|
||||
* An array map with all the pending images associated with their URLs
|
||||
*/
|
||||
private static ArrayMap<String, Thread> pendingOperation = null;
|
||||
|
||||
/**
|
||||
* The context of the operation
|
||||
*/
|
||||
private Context mContext;
|
||||
|
||||
/**
|
||||
* Target view for the image
|
||||
*/
|
||||
private ImageView imageView;
|
||||
|
||||
/**
|
||||
* The URL of the image
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* The file object of the image
|
||||
*/
|
||||
private File file;
|
||||
|
||||
/**
|
||||
* Constructor of the runnable
|
||||
*
|
||||
* @param context The context of the application
|
||||
* @param imageView The imageView of the image
|
||||
* @param url The URL of the image
|
||||
*/
|
||||
ImageLoadRunnable(Context context, ImageView imageView, String url){
|
||||
|
||||
//Check if the list of pending operations has to be initialized or not
|
||||
if(pendingOperation == null)
|
||||
pendingOperation = new ArrayMap<>();
|
||||
|
||||
//Save the values
|
||||
this.imageView = imageView;
|
||||
this.url = url;
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
//Determine the filename for the requested URL
|
||||
String filename = ImageLoadUtils.IMAGE_CACHE_DIRECTORY + ImageLoadUtils.get_file_name(url);
|
||||
|
||||
//Create file object
|
||||
file = new File(mContext.getCacheDir(),filename);
|
||||
|
||||
//Check no thread is already running for the following image
|
||||
if(!pendingOperation.containsKey(url)){
|
||||
|
||||
//Check if a file exist or not
|
||||
if(file.exists()){
|
||||
|
||||
//Then the file can be loaded in a bitmap
|
||||
load_image();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
//Create the thread and start it
|
||||
Thread thread = new Thread(new ImageDownloadRunnable(url, file));
|
||||
pendingOperation.put(url, thread);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
//Get the thread
|
||||
Thread operation = pendingOperation.get(url);
|
||||
|
||||
//If we couldn't get the thread, this is an error
|
||||
if(operation == null){
|
||||
Log.e("ImageLoadManagerRunnabl", "run : Couldn't get thread !");
|
||||
return;
|
||||
}
|
||||
|
||||
if(operation.isAlive()) {
|
||||
try {
|
||||
//Wait for the thread to finish
|
||||
operation.join();
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Remove the thread from the pending list
|
||||
pendingOperation.remove(url);
|
||||
|
||||
//Load the image
|
||||
load_image();
|
||||
}
|
||||
|
||||
/**
|
||||
* Once the image was downloaded (if it wasn't already) load the image into a bitmpa object
|
||||
* The apply to the final image view
|
||||
*/
|
||||
private void load_image(){
|
||||
|
||||
//Check if the file exists
|
||||
if(!file.exists()){
|
||||
Log.e("ImageLoadManagerRunnabl", "load_image : file does not exists but it should !");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
//Load the image
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(is);
|
||||
is.close();
|
||||
|
||||
//Check if bitmap failed to read
|
||||
if(bitmap == null){
|
||||
//Return error
|
||||
Log.e("ImageLoadManagerRunnabl", "Image file could not be read, therefore it was" +
|
||||
"deleted");
|
||||
|
||||
//Delete file
|
||||
file.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
//Apply the bitmap on the image view (register operation)
|
||||
imageView.post(new ImageLoadApplyRunnable(imageView, bitmap));
|
||||
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.communiquons.android.comunic.client.data;
|
||||
package org.communiquons.android.comunic.client.data.ImageLoad;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
@ -9,6 +9,8 @@ import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.communiquons.android.comunic.client.data.Utilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
@ -23,10 +25,13 @@ import java.net.URL;
|
||||
/**
|
||||
* Web image loader and renderer
|
||||
*
|
||||
* Warning : Using ImageLoadTask is a quite bad idea to load multiple images,
|
||||
* ImageLoad class should be preferred
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
* Created by pierre on 11/8/17.
|
||||
*/
|
||||
|
||||
@Deprecated
|
||||
public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
/**
|
||||
@ -44,11 +49,6 @@ public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
||||
*/
|
||||
private Context mContext;
|
||||
|
||||
/**
|
||||
* The main folder in the cache directory that stores the file
|
||||
*/
|
||||
private final String IMAGE_CACHE_DIRECTORY = "img_cache/";
|
||||
|
||||
/**
|
||||
* Image file object
|
||||
*/
|
||||
@ -80,12 +80,12 @@ public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
||||
protected Void doInBackground(Void... param) {
|
||||
|
||||
//Determine the file name for the view
|
||||
String filename = get_file_name(url);
|
||||
String filename = ImageLoadUtils.get_file_name(url);
|
||||
if (filename == null) {
|
||||
Log.e("ImageLoadTask", "Couldn't generate file storage name !");
|
||||
return null; //An error occured
|
||||
}
|
||||
String full_filename = IMAGE_CACHE_DIRECTORY + filename;
|
||||
String full_filename = ImageLoadUtils.IMAGE_CACHE_DIRECTORY + filename;
|
||||
|
||||
//Try to open the file
|
||||
img_file = new File(mContext.getCacheDir(), full_filename);
|
||||
@ -177,24 +177,13 @@ public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the file name, based on the URL name
|
||||
*
|
||||
* @param url The URL of the file
|
||||
* @return The name of the file, composed of characters that can be used in filename
|
||||
*/
|
||||
private String get_file_name(String url){
|
||||
return Utilities.sha1(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cache images files parent directory if it does not exist
|
||||
*
|
||||
* @return True in case of success
|
||||
*/
|
||||
private boolean create_parent_directory(){
|
||||
File parent = new File(mContext.getCacheDir(), IMAGE_CACHE_DIRECTORY);
|
||||
File parent = new File(mContext.getCacheDir(), ImageLoadUtils.IMAGE_CACHE_DIRECTORY);
|
||||
|
||||
//Check if parent directory already exists
|
||||
if(parent.exists())
|
@ -0,0 +1,29 @@
|
||||
package org.communiquons.android.comunic.client.data.ImageLoad;
|
||||
|
||||
import org.communiquons.android.comunic.client.data.Utilities;
|
||||
|
||||
/**
|
||||
* Image loading utilities
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
* Created by pierre on 11/18/17.
|
||||
*/
|
||||
|
||||
class ImageLoadUtils {
|
||||
|
||||
/**
|
||||
* The main folder in the cache directory that stores the file
|
||||
*/
|
||||
static final String IMAGE_CACHE_DIRECTORY = "img_cache/";
|
||||
|
||||
/**
|
||||
* Get the file name, based on the URL name
|
||||
*
|
||||
* @param url The URL of the file
|
||||
* @return The name of the file, composed of characters that can be used in filename
|
||||
*/
|
||||
static String get_file_name(String url){
|
||||
return Utilities.sha1(url);
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package org.communiquons.android.comunic.client.data.friendsList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
@ -11,7 +12,8 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.communiquons.android.comunic.client.R;
|
||||
import org.communiquons.android.comunic.client.data.ImageLoadTask;
|
||||
import org.communiquons.android.comunic.client.data.ImageLoad.ImageLoadManager;
|
||||
import org.communiquons.android.comunic.client.data.ImageLoad.ImageLoadTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -51,8 +53,7 @@ public class FriendsAdapter extends ArrayAdapter<FriendUser> {
|
||||
|
||||
//Update user account image
|
||||
ImageView user_image = listItemView.findViewById(R.id.fragment_friendslist_item_accountimage);
|
||||
new ImageLoadTask(getContext(), friendUser.getUserInfo().getAcountImageURL(), user_image)
|
||||
.execute();
|
||||
ImageLoadManager.load(getContext(), friendUser.getUserInfo().getAcountImageURL(), user_image);
|
||||
|
||||
//Update user name
|
||||
TextView user_name = listItemView.findViewById(R.id.fragment_friendslist_item_fullname);
|
||||
|
@ -14,7 +14,7 @@ import android.widget.TextView;
|
||||
import org.communiquons.android.comunic.client.R;
|
||||
import org.communiquons.android.comunic.client.data.Account.AccountUtils;
|
||||
import org.communiquons.android.comunic.client.data.DatabaseHelper;
|
||||
import org.communiquons.android.comunic.client.data.ImageLoadTask;
|
||||
import org.communiquons.android.comunic.client.data.ImageLoad.ImageLoadTask;
|
||||
import org.communiquons.android.comunic.client.data.UsersInfo.GetUsersInfos;
|
||||
import org.communiquons.android.comunic.client.data.UsersInfo.UserInfo;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user