mirror of
https://github.com/pierre42100/ComunicAndroid
synced 2024-11-23 22:09:30 +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.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -9,6 +9,8 @@ import android.support.v4.content.ContextCompat;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import org.communiquons.android.comunic.client.data.Utilities;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@ -23,10 +25,13 @@ import java.net.URL;
|
|||||||
/**
|
/**
|
||||||
* Web image loader and renderer
|
* 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
|
* @author Pierre HUBERT
|
||||||
* Created by pierre on 11/8/17.
|
* Created by pierre on 11/8/17.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,11 +49,6 @@ public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
|||||||
*/
|
*/
|
||||||
private Context mContext;
|
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
|
* Image file object
|
||||||
*/
|
*/
|
||||||
@ -80,12 +80,12 @@ public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
|||||||
protected Void doInBackground(Void... param) {
|
protected Void doInBackground(Void... param) {
|
||||||
|
|
||||||
//Determine the file name for the view
|
//Determine the file name for the view
|
||||||
String filename = get_file_name(url);
|
String filename = ImageLoadUtils.get_file_name(url);
|
||||||
if (filename == null) {
|
if (filename == null) {
|
||||||
Log.e("ImageLoadTask", "Couldn't generate file storage name !");
|
Log.e("ImageLoadTask", "Couldn't generate file storage name !");
|
||||||
return null; //An error occured
|
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
|
//Try to open the file
|
||||||
img_file = new File(mContext.getCacheDir(), full_filename);
|
img_file = new File(mContext.getCacheDir(), full_filename);
|
||||||
@ -177,24 +177,13 @@ public class ImageLoadTask extends AsyncTask<Void, Void, Void> {
|
|||||||
return true;
|
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
|
* Create cache images files parent directory if it does not exist
|
||||||
*
|
*
|
||||||
* @return True in case of success
|
* @return True in case of success
|
||||||
*/
|
*/
|
||||||
private boolean create_parent_directory(){
|
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
|
//Check if parent directory already exists
|
||||||
if(parent.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;
|
package org.communiquons.android.comunic.client.data.friendsList;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -11,7 +12,8 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.communiquons.android.comunic.client.R;
|
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;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@ -51,8 +53,7 @@ public class FriendsAdapter extends ArrayAdapter<FriendUser> {
|
|||||||
|
|
||||||
//Update user account image
|
//Update user account image
|
||||||
ImageView user_image = listItemView.findViewById(R.id.fragment_friendslist_item_accountimage);
|
ImageView user_image = listItemView.findViewById(R.id.fragment_friendslist_item_accountimage);
|
||||||
new ImageLoadTask(getContext(), friendUser.getUserInfo().getAcountImageURL(), user_image)
|
ImageLoadManager.load(getContext(), friendUser.getUserInfo().getAcountImageURL(), user_image);
|
||||||
.execute();
|
|
||||||
|
|
||||||
//Update user name
|
//Update user name
|
||||||
TextView user_name = listItemView.findViewById(R.id.fragment_friendslist_item_fullname);
|
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.R;
|
||||||
import org.communiquons.android.comunic.client.data.Account.AccountUtils;
|
import org.communiquons.android.comunic.client.data.Account.AccountUtils;
|
||||||
import org.communiquons.android.comunic.client.data.DatabaseHelper;
|
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.GetUsersInfos;
|
||||||
import org.communiquons.android.comunic.client.data.UsersInfo.UserInfo;
|
import org.communiquons.android.comunic.client.data.UsersInfo.UserInfo;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user