How to stop calling the onDraw() function on a View? - android

Im clearing up the bitmaps i load in one activity before i more into the other activity.
eg:
pic1 = null;
System.gc();
nextActivityIntent = new Intent(ThisActivity,NextActivity.class);
ThisActivity.startActivityForResult(nextActivityIntent,123);
But the problem is system calls onDraw some times after i call "pic1=null". When it happens the application crashes with pointing a NullPoint Exception.
Cab any one suggest me how to stop calling onDraw() after setting the "pic1=null". Can i use synchornized to make this happen.

You can try view.setWillNotDraw(true); (link here), but I'm not sure it will prevent it.
On a side note, if your first activity will finish, there is no need to set the bitmap to null nor to call System.gc();. The bitmaps will be recovered anyway after the activity is destroyed.
If for some reason you still want to do it, you should do that inside the onDestroy() callback to avoid any drawing issues. Check the Activity lifecycle for more details.

Related

Invalidate is failing to call onDraw when returning to an activity that has a custom view

I have inherited some code hence I don't have true freedom to change it. :(
I have a main activity, from which other activities (I will refer to these as sub activities from now on) are called. Whenever one of these completes, it calls finish and returns data to the main activity.
Each activity (including the main one) has a bar on the top that displays a custom view. The custom view contains a canvas which has a drawing that is dependant upon the state of the network.. i.e. wifi/mobile etc...
Since that 'state' data never changes, it's held within a singleton and the view gets data from the singleton to define what it draws. That is working with no issues, i.e. the data is always as I expect it.
When I first launch the MainActivity, as the network changes, the data changes and each call to 'invalidate' the view receives a system call to 'onDraw' as I would expect.
In each of the sub activities the same is again true.
Upon finishing a sub activity and returning to the mainActivity, calls to invalidate no longer cause a call to onDraw to occur.
I have looked at this for quite a while now and just cannot figure out what is going wrong.
In my constructor I have:
setWillNotDraw(false);
Whenever the data changes the following methods are called:
invalidate();
requestLayout();
Now, there's one more thing... upon returning to the activity at that immediate point, I refresh and this DOES draw correctly, i.e. invalidate does trigger an onDraw call... any subsequent network changes (which are propogated) fail to result in the onDraw call.
I'm wondering if this is to do with the view somehow being detached. I can see that 'onDetachedFromWindow' is called, however the trigger for this is the destruction of the subactivity, hence I don't see why that should affect the MainActivity but it's the only thing I can think of.
I'm hoping I've provided enough information for someone to help me...
Well, in the end my answer has very little to do with the question and I guess this is an example of how an issue can be solved by going back to absolute basics and checking for the obvious.
My activities all inherit from an abstract activity. Within that activity there is an instance of the view. The views in which I was having trouble were using that declaration as opposed to having their own instance, hence behaviour from one activity was then affecting another inadvertently.
So, if I'd been able to post up all the code, I'm sure someone else would have spotted this but, unfortunately I couldn't in this instance.
Still, whilst this posting doesn't provide a resolution that will help others, maybe it does say... step back and check the obvious first!

Android Bitmap recycling

Disclaimer: I read about 20 existing questions. Unfortunately none of them solved my problem.
I have an activity. This activity gets a Bitmap from a global/static class C and sets the bitmap to an ImageView. When the activity is finished and I try to reopen the activity, I get the java.lang.RuntimeException: Canvas: trying to use a recycled bitmap exception. I don't call Bitmap.recycle() at any point. Also, I do not delete the bitmap reference in class C. I tried the following but they didn't work:
Call ImageView.setDrawingCacheEnabled(false)
Before setting the bitmap for ImageView, make a deep copy (via Bitmap.copy() method)
Also, I put some log statements throughout the activity lifecycle. Inside onDestroy(), before calling super.onDestroy() I check and make sure that the bitmap is not recycled (through Bitmap.isRecycled())
How can I fix this issue?
The culprit turned out to be RemoteControlClient.MetadataEditor.apply(), it does call recycle() for bitmaps passed to it.
I had similar issue with ImageViews when reopening the activity (e.g. after screen is waked). The problem lies not in Bitmap itself, but in ImageView. My solution was to set ImageView's setImageBitmap to null on activity's onPause() and call setImageBitmap(theBitmap) on activity's onResume().

When are views 'killed' in android?

When are the view's 'killed' and no more exist in Android ?
For example, suppose I have an asynctask and I run some network related stuff in the doInBackground() method. Then, I need to update my UI views in the onPostExecute() method.
Assume my doInBackground() took a while and while it was being processed the user moved back or even pressed the home button. The task will continue because doInBackground runs on a seperate thread, however, once it is finished and onPostExecute is called to update the views, the views might not be there.
Even if the activity is not visible (either gone to home screen, or another activity), what happens when the views try to get accessed and modifed ? How long do they stay in the 'heap/memory/whatever', do they get garbage collected after onDestroy ? or they stay around after that ?
I know a way to not get into this hastle is to use a switch that gets turned on and off inside onResume and onStop and check it before updating the views in onPostExecute, but I am unsure if this is solid approach applied in the android apps ? if not, what is the suggested way ?
A view inside an activity can be considered like any other object within the activity class. It will stay in the memory as long as it is referenced by the some other object. This object could be another view or activity. This means the view will be gone if:
1) The activity or the parent view remove it removeView() from the view tree thus no one keeps a reference to it.
2) The activity or parent view that contain the view are destroyed/gone from the memory.
If the activity is not visible (either gone to home screen, or another
activity), what happens when the views try to get accessed and modifed
? How long do they stay in the 'heap/memory/whatever', do they get
garbage collected after onDestroy ? or they stay around after that ?
You can access the view, as long as your activity is available. And you can find more about that by reading the Activity Lifecycle
When you try to access a view that is gone from the memory, you will get a NullPointerException. The simple & solid way how you can handle onPostExecute is by checking for null before updating, example:
// inside onPostExecute
if(textView != null) {
textView.setText("Background Method Finished");
}
The advantage of this approach is:
1) You do not have to explicitly keep track of show/hide.
2) Sometimes, view is not on the screen does not mean that it gone from the memory. For example, let say your AsyncTask finishes while your activity is paused/stopped not destroyed. In this case, you can still update the view, so that when the activity is resumed the update is visible and is not lost.
Cancel async task when user leave from that activity. After cancelled task, onPostExecute will not called and capture cancel event in onCanceled event in async task class.
You have many ways
1.You can cancel the asynctask
2.You can kill the process,so there will be nothing in the menory or heap.

Android: unable to change ImageView at run time

I am using ImageView in my example. I set Images as background of imageview in xml. Now I want to change this image background of Imageview at run time.
this is my java code.
changeImage()
{
ImageView imgview=(ImageView)findViewById(R.id.imageView1);
imgview.setImageResource(R.drawable.headerhindi);
}
I am calling this method from onCreate(). First time my method works fine. but when I redirect again to my activity onCreate() using startActivity(myActivityIntent); this method does not works properly means Images does not change according to this method. By default images which is set in xml is shown.
Please help me to find out the solution.
Thank you in advance.
Try moving the call to changeImage() to onResume().
I haven't tested it, but I have a feeling that what's happening is that when you call startActivity() to start the activity again, the activity was not destroyed yet so onCreate() is not called again as per the activity lifecycle:
http://developer.android.com/images/activity_lifecycle.png. Just a hunch though.
How to you redirect to your activity onCreate ?
If your activity was already running, it skips onCreate and goes directly to the Started state.
You probably want to move your changeImage() to the onStart() method which get called on creation and resuming.
You can see full explanations here: Managing the Activity Lifecycle
※ The main difference for you between onStart() and onResume() would be that onStart() is called before the activity becomes visible while onResume() is called after.

onCreate not called when restarting activity after it is destroyed

When I exit my app (by pressing back or the home button) the Activitys onDestroy() method is called (where I do lots of clean up with bitmaps).
When I reopen the app, onCreate() does not get called... it goes straight to onStart(), despite the fact that the Activity was finished. This is causing a "trying to use a recycled bitmap" error.
Is there a way to ensure that onCreate() is always called after an Activity is destroyed?
EDIT: I was mistaken. onCreate() IS being called. However, I am still getting the "trying to use a recycled bitmap" error. If onCreate() is going through all of it's steps, wouldn't any recycled bitmaps be reloaded?
Your app must be doing something to forcefully ensure that onDestroy gets called, because if you look at the Activity lifecycle there's no path to get back to onStart from onDestroy that doesn't include onCreate. In reality, an Activity unwinds its initialization with reverse callbacks to the ones that bring it into the resumed state. Take a look at the official documentation here Perhaps you're calling the finish() method somewhere to force quite the Activity?
when you press the home button , the activity is not destroyed , it is just sent to background , and the method onPause() is called, and when you launch it again , the method onResume() will be executed, the method onDestroy() is executed when you press the back button or when you call the method finish() to force the activity to be destroyed , and then when you try to re launch your activity , the onCreate() will be executed.
refer this
The problem was with how I was setting the ImageView image. My original way to load an image from /res was:
image.setImageDrawable(getResources().getDrawable(R.drawable.myImage)); //WRONG!!!!
apparently if you recycled a bitmap, the above code will not reallocate memory for the bitmap, and your program will crash when it tries to draw that ImageView.
The correct way to load a bitmap that has been recycled (or at least, the way that solved my problem) is:
image.setImageDrawable(new BitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.myImage))); //correct!
It still doesn't answer my question as to why, after exiting the app, and onDestroy is called, that when I re-enter the app, it is looking for a recycled bitmap. In theory the app should be starting up from scratch.

Categories

Resources