ImageView updating seconds after progressDialog - android

I am using asynckTask to decode a file and onPostExecute I setImageBitmap and call progressDialog.dismiss() but after the progressDialog is dismissed the imageView take a few seconds to show the image. What I want is the progressDialog to disappear only when the image view is ready for the user. My code is below:
class MyTask extends AsyncTask<String, Integer, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String mainImageString;
private Context context;
ProgressDialog progressDialog;
public MyTask(ImageView imageView, Context mContext) {
imageViewReference = new WeakReference<ImageView>(imageView);
context = mContext;
}
#Override
protected void onPreExecute() {
progressDialog= ProgressDialog.show(MyClass.this, "Progress Dialog Title Text","Process Description Text", true);
}
// Decode image in background.
#Override
protected Bitmap doInBackground(String... params) {
mainImageString = params[0];
return BitmapFactory.decodeFile(mainImageString);
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
progressDialog.dismiss();
}
}
}
}

When you are setting your Bitmap basically you are "building" it on the UI thread. What I recommend is to call setImageBitmap in your doInBackground callback and then dismiss the dialog.

You can do this...
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
handler.postDelayed(new Runnable() {
public void run() {
progressDialog.dismiss();
}
}, 1000); //time for image to appear in image view
}
}
Please note this is not a foolproof way..but this what-easy way-currently I can think of..
Other hack I can think about is to extend ImageView and override onDraw().call super() in onDraw(),once the call to super() returns then dismiss the dialog box.This is more accurate way of doing it.
something like this:
onDraw(){
super();
onDismissDialogBox()//send an even to activity to dismiss dialog box
}

Related

Listview not loading images till I scroll the screen

I am using an async call inside my Custom Adapter class to load images in a Listview. However, the images are not shown till I scroll up/down atleast slightly. Please let me know what might be the reason. Thanks for your help.
private class LoadImage extends AsyncTask<Void, Void, Void>
{
private String fileName = null;
private ImageView imgViewToLoad = null;
LoadImage(String fileName, ImageView imgViewToLoad)
{
this.fileName = fileName;
this.imgViewToLoad = imgViewToLoad;
}
#Override
protected Void doInBackground(Void... args)
{
return null;
}
//This is executed on main UI thread
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Utils.mImageFetcher.loadImage(fileName, imgViewToLoad);
}
}
This is in my getView()
----------------------
ViewHolderIncomingImg holderInImg = null;
if (null != convertView &&
(convertView.getTag() instanceof ViewHolderIncomingImg && !isFirstMsg))
{
holderInImg = (ViewHolderIncomingImg) convertView.getTag();
if (!multiSelectionMode)
{
if (!mSelectedItemsIds.get(position) && convertView.isActivated())
convertView.setActivated(false);
}
}
else
{
convertView = mInflater.inflate(R.layout.conv_list_item_incoming_img, parent, false);
holderInImg = new ViewHolderIncomingImg();
..............
new LoadImage(convRowItems.get(position).getMessage(), holderInImg.image).execute();
As Listview use the concept of recycling its view. The images are not showing when the async call finish.
So go for listview lazy loading approach it will help you.

Undesired delay at beginning an Acitivity

I am working with some Acitivitys , it's working pretty well. But i am having a strange delay on it.
And I figure it out that, it was about this part of the code, where I am loading stored image in the SDCard.
if(p.getAdress() != null){
Bitmap bitmap = BitmapFactory.decodeFile(p.getAdress());
new_image.setBackgroundDrawable(null);
new_image.setImageBitmap(bitmap);
}
Why this simple code is taking too long to execute?
How to solve it?
If I take this code off, everything works as i wished.
You shouldn't load large bitmaps directly on the UI thread.
Actually, the best reference to loading large Bitmaps efficiently can be found here.
And right here you can find good information on how you can load them using an AsyncTask.
This is the method they show you there (you can even download the sample!)
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
#Override
protected Bitmap doInBackground(Integer... params) {
data = params[0];
return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
}
// Once complete, see if ImageView is still around and set bitmap.
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
public void loadBitmap(int resId, ImageView imageView) {
if (cancelPotentialWork(resId, imageView)) {
final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
final AsyncDrawable asyncDrawable =
new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
imageView.setImageDrawable(asyncDrawable);
task.execute(resId);
}
}
Your can try this way. It help you
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
if(p.getAdress() != null){
Bitmap bitmap = BitmapFactory.decodeFile(p.getAdress());
new_image.setBackgroundDrawable(null);
new_image.setImageBitmap(bitmap);
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}

Passing parameters into AsyncTask

Hi so i'm trying to grab a image from a url link via AsyncTask, the function to grab the image itself work fine. but what i trying to do is to pass the src variable into a asyncTask which seems to be not working for me. the return will be blank.
here is the code:
private AsyncTask<String, Void, Drawable> task2;
Drawable profile;
public Drawable getProfile(String src){
task2 = new AsyncTask<String, Void, Drawable>() {
ProgressDialog dialog2;
InputStream is;
Drawable d;
#Override
protected void onPreExecute(){
dialog2 = new ProgressDialog(Thoughts.this, ProgressDialog.STYLE_SPINNER);
dialog2.setMessage("Loading Data...");
dialog2.setCancelable(false);
dialog2.setCanceledOnTouchOutside(false);
dialog2.show();
}
#Override
protected Drawable doInBackground(String... src) {
try
{
is = (InputStream) new URL(src[0]).getContent();
d = Drawable.createFromStream(is, "src name");
return d;
}catch (Exception e) {
e.toString();
return null;
}
}
#Override
protected void onPostExecute(Drawable result2) {
profile = result2;
dialog2.dismiss();
}
};
task2.execute(src);
return profile;
}
and i call it like this at the onCreate();
Drawable p4 = getProfile("http://..../xyz.jpg");
Drawable p5 = getProfile("http://..../xyz.jpg");
ImageView thoughtsProfilePic =(ImageView) findViewById(R.id.ivProfilePicData);
ImageView thoughtsProfilePic1 =(ImageView) findViewById(R.id.ivProfilePicData1);
thoughtsProfilePic.setImageDrawable(p4);
thoughtsProfilePic1.setImageDrawable(p5);
AsyncTask help you do an asynchronous job. In your code, I can see you return Drawable right after calling it. But at that moment, the your asynctask hasn't completed yet and drawable still null.
task2.execute(src);
return profile;
If you want set drawable resource when complete job in asynctask, just put your ImageView into your method. It should be:
public void getProfile(String src, final ImageView v){
#Override
protected void onPostExecute(Drawable result2) {
// set drawable for ImageView when complete.
v.setImageDrawable(result2);
dialog2.dismiss();
}
task2.excute(src);
//do not need return anything.
}
Use it:
ImageView thoughtsProfilePic =(ImageView) findViewById(R.id.ivProfilePicData);
getProfile("http://..../xyz.jpg", thoughtsProfilePic );
Hope this help.
Update:
There is no way to return value from asynchronous method directly, here is another choice.
First, create an interface to notify when complete job.
public interface INotifyComplete{
public void onResult(Drawable result);
}
Then your activity class should look like:
public class YourActivity extends Activity implement INotifyComplete{
private Drawable res1;
private Drawable res2;
public void onResult(Drawable result){
if(result == res1){
// do something with resource 1
ImageView thoughtsProfilePic =(ImageView) findViewById(R.id.ivProfilePicData);
thoughtsProfilePic.setImageDrawable(result);
}
if(result == res2){
// do something with resource 2
}
}
void someMethod(){
// you can use this way to call
getProfile("http://..../xyz.jpg", res1, YourActivity.this);
//or this
getProfile("http://..../xyz.jpg", res2, new INotifyComplete(){
public void onResult(Drawable result){
// result is res2, so don't need to check
}
});
}
public void getProfile(String src, final Drawable res, final INotifyComplete notify){
//don't need store asynctask instance
AsyncTask<String, Void, Drawable> task2 = new AsyncTask<String, Void, Drawable>(){
// do something ...
protected void onPostExecute(Drawable result2) {
dialog2.dismiss();
// you will set the value to your drawable then notify it when complete job
res = result2;
notify.onResult(res);
}
}
task2.excute();
}
}
write a public member function in your activity which returns drawable and just call the function in doInBackground() method of your asyncTask class.
Drawable downloadImage(){
//write code here to download image so you can return any dataType
}
now just call this function in doInBackground() method and save returned result in some variable of your activity.
like
void doInBackground(){
drawableVariable = downloadImage();
}
Edit: asyncTask is your background thread and is not UI thread so if you want to do any UI work then you will have to perform that work in UI thread by runOnUiThread() method
runOnUiThread(new Runnable() {
#Override
public void run() {
/* update your UI here for example what you are doing something */;
profile = result2;
}
});

How to stop ( kill ) AsyncTask in android

Hi I am new to android:
I am displaying image thumbs in GridView. For better performance I am loading it asynchronously.
My AsyncTask is as:
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
private String image_path;
public BitmapWorkerTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(Integer... params) {
data = params[0];
Bitmap picture = BitmapFactory.decodeFile(image_path);
int width = picture.getWidth();
int height = picture.getHeight();
float aspectRatio = (float) width / (float) height;
int newWidth = 98;
int newHeight = (int) (98 / aspectRatio);
return picture = Bitmap.createScaledBitmap(picture, newWidth,
newHeight, true);
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
public void onDismiss(DialogInterface dialog) {
this.cancel(true);
}
}
and Calling form:
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListRowHolder listRowHolder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.ll_sponsor_list_item,
parent, false);
listRowHolder = new ListRowHolder();
listRowHolder.imgSponsor = (ImageView) convertView
.findViewById(R.id.imggrid_item_image);
convertView.setTag(listRowHolder);
} else {
listRowHolder = (ListRowHolder) convertView.getTag();
}
try {
BitmapWorkerTask task = new BitmapWorkerTask(
listRowHolder.imgSponsor);
task.image_path = ImageName.get(position);
task.execute(1);
} catch (Exception e) {
Toast.makeText(ctx, e + "", Toast.LENGTH_SHORT).show();
}
return convertView;
}
The problem here is the tasks are running in background even I clicked on back button.
Use cancel() to stop a AsyncTask:
task.cancel(true);
The documentation of AsyncTask provides some additional details in the 'Cancelling a task' section:
A task can be cancelled at any time by invoking cancel(boolean). Invoking
this method will cause subsequent calls to isCancelled() to return true.
After invoking this method, onCancelled(Object), instead of
onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
First, you need to keep references to every asynctask you execute. When the activity pauses, you should iterate through the references to the asynctask and cancel them with cancel(). You should also call get() on each of the asynctasks. This will make sure that the UI thread waits until the asynctask is finished before changing activities.
Use cancel(true) if you want the asynctask's thread to be interrupted, or use cancel(false), and at points in your doInBackground() method you should check isCancelled() and return.
For safety you must be very careful with asynctasks. Check out this article on safely handling them.
Make something like this
private class myAsyncTask extends AsyncTask<Void, String, Void> {
private boolean isTaskCancelled = false;
public void cancelTask(){
isTaskCancelled = true;
}
private boolean isTaskCancelled(){
return isTaskCancelled;
}
protected Void doInBackground( Void... ignoredParams ) {
//Do some stuff
if (isTaskCancelled()){
return;
}
}
protected void onPostExecute( Void array )
{
//Do something
}
protected void onProgressUpdate(String... values)
{
//Do something
}
}
When you press back on the Activity, put the asynctask in cancelled mode, so it will stop executing things.
Check for the cancelled method in every step you make in your asynctask, to stop it on the next line

Android: alert dialog in a class without activity

i have this class:
public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageFromWeb ifw;
private String url;
private final WeakReference<ImageView> imageViewReference;
public DownloadImageTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(String... params) {
url = params[0];
try {
return BitmapFactory.decodeStream(new URL(url).openConnection().getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap result) {
if (isCancelled()) {
result = null;
}
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(result);
}
}
}
#Override
protected void onPreExecute() {
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
---------> imageView.setImageResource(R.drawable.pw);
}
}
}
}
and the main activity:
public class ImageFromWeb extends Activity {
private String path = "http://....";
private ImageView imageView;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
ImageView mChart = (ImageView) findViewById(R.id.imview);
mChart.setTag(path);
new DownloadImageTask(mChart).execute(path);
}
}
I want to put in the point of arrow(in DownloadImageTask class) an alert dialog! How can i do this? Because this class isn't an activity.
thanks :)
change the constructor and pass a Context object
Context mContext;
public DownloadImageTask(ImageView imageView,Context mContext) {
imageViewReference = new WeakReference<ImageView>(imageView);
this.mContext = mContext;
}
Now you can use this Context to create dialogs
You can even cast mContext to your Activity class and call functions within your Activity
Move the Async Task to your activity and use that to call your DownloadImageTask class & methods. This will make your life a lot easier.
pass a Activity instance to the class where you want to display dialog, and check
if(!actvity.isFinishing){
//show dialog
}
You can have a static Context in your Application like this:
public static Context CurrentContext;
and a custom abstract Activity that sets currentContext upon creation like this:
public abstract class CustomActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.CurrentContext = this;
}
}
Then you would get context like this:
AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(MyApplication.CurrentContext);
dlgBuilder.setTitle("Context Example");
dlgBuilder.setMessage("I am being shown from the application Static context!");
dlgBuilder.setNeutralButton("Ok", null);
dlgBuilder.show();
This way you never have to worry about context wether you are in a background task or directly in an Activity it will work for most cases.
hope this helps!

Categories

Resources