Load bitmaps in background in chat in order to make UI smoother

This commit is contained in:
Sylvain Berfini 2015-05-15 17:39:11 +02:00
parent 28a6f800a5
commit 617beb7db6
2 changed files with 128 additions and 37 deletions

View file

@ -283,7 +283,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
topBar.setVisibility(View.GONE);
}
contactPicture.setVisibility(View.GONE);
scrollToEnd();
//scrollToEnd();
}
public void hideKeyboardVisibleMode() {
@ -292,7 +292,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
if (isOrientationLandscape && topBar != null) {
topBar.setVisibility(View.VISIBLE);
}
scrollToEnd();
//scrollToEnd();
}
class ChatMessageAdapter extends BaseAdapter {

View file

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
@ -33,9 +34,13 @@ import org.linphone.mediastream.Log;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.text.Html;
import android.text.Spannable;
@ -95,7 +100,8 @@ public class BubbleChat {
private ImageView statusView;
private LinphoneChatMessage nativeMessage;
private LinphoneChatMessage.LinphoneChatMessageListener fileTransferListener;
private static final int SIZE_MAX = 2048;
private Context mContext;
private static final int SIZE_MAX = 512;
@SuppressLint("InflateParams")
public BubbleChat(final Context context, LinphoneChatMessage message, LinphoneChatMessage.LinphoneChatMessageListener listener) {
@ -104,6 +110,7 @@ public class BubbleChat {
}
nativeMessage = message;
fileTransferListener = listener;
mContext = context;
view = new RelativeLayout(context);
LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
@ -160,40 +167,7 @@ public class BubbleChat {
});
} else {
imageView.setVisibility(View.VISIBLE);
Bitmap bm = null;
if (appData.startsWith("content")) {
try {
bm = MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.parse(appData));
} catch (FileNotFoundException e) {
Log.e(e);
} catch (IOException e) {
Log.e(e);
}
} else {
bm = BitmapFactory.decodeFile(appData);
appData = "file://" + appData;
}
if (bm != null) {
if (bm.getWidth() > bm.getHeight() && bm.getWidth() > SIZE_MAX) {
bm = Bitmap.createScaledBitmap(bm, SIZE_MAX, (SIZE_MAX * bm.getHeight()) / bm.getWidth(), false);
} else if (bm.getHeight() > bm.getWidth() && bm.getHeight() > SIZE_MAX) {
bm = Bitmap.createScaledBitmap(bm, (SIZE_MAX * bm.getWidth()) / bm.getHeight(), SIZE_MAX, false);
}
imageView.setImageBitmap(bm);
imageView.setTag(appData);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse((String)v.getTag()), "image/*");
context.startActivity(intent);
}
});
}
loadBitmap(appData, imageView);
}
} else {
TextView msgView = (TextView) layout.findViewById(R.id.message);
@ -340,4 +314,121 @@ public class BubbleChat {
public int getId() {
return nativeMessage.getStorageId();
}
public void loadBitmap(String path, ImageView imageView) {
if (cancelPotentialWork(path, imageView)) {
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
Bitmap defaultBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_photo_default);
final AsyncBitmap asyncBitmap = new AsyncBitmap(mContext.getResources(), defaultBitmap, task);
imageView.setImageDrawable(asyncBitmap);
task.execute(path);
}
}
private class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
public String path;
public BitmapWorkerTask(ImageView imageView) {
path = null;
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(String... params) {
path = params[0];
Bitmap bm = null;
if (path.startsWith("content")) {
try {
bm = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), Uri.parse(path));
} catch (FileNotFoundException e) {
Log.e(e);
} catch (IOException e) {
Log.e(e);
}
} else {
bm = BitmapFactory.decodeFile(path);
path = "file://" + path;
}
if (bm != null) {
if (bm.getWidth() >= bm.getHeight() && bm.getWidth() > SIZE_MAX) {
bm = Bitmap.createScaledBitmap(bm, SIZE_MAX, (SIZE_MAX * bm.getHeight()) / bm.getWidth(), false);
} else if (bm.getHeight() >= bm.getWidth() && bm.getHeight() > SIZE_MAX) {
bm = Bitmap.createScaledBitmap(bm, (SIZE_MAX * bm.getWidth()) / bm.getHeight(), SIZE_MAX, false);
}
}
return bm;
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask && imageView != null) {
imageView.setImageBitmap(bitmap);
imageView.setTag(path);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse((String)v.getTag()), "image/*");
mContext.startActivity(intent);
}
});
}
}
}
}
static class AsyncBitmap extends BitmapDrawable {
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
public AsyncBitmap(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
public static boolean cancelPotentialWork(String path, ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final String bitmapData = bitmapWorkerTask.path;
// If bitmapData is not yet set or it differs from the new data
if (bitmapData == null || bitmapData != path) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was cancelled
return true;
}
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncBitmap) {
final AsyncBitmap asyncDrawable = (AsyncBitmap) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
}