I know this has probably been addressed, however, I am having memory leak issues in my Android app. I have it cycle through a differant picture in the users library every time they push a button. This works fine for the first couple then throws an out of memory exception. I have looked around and though I understood that the pictures are being stored on the heap(?) even after it is not being pointed at. Is there a way I can force this to clean up so I am not getting the error? I have tried the following....
private void setImage() throws RemoteException{
view.setBackgroundDrawable(null);
currentBackground = Drawable.createFromPath(backgroundImageService.getCurrentImageLocation());
view.setBackgroundDrawable(currentBackground);
}
UPDATE:: Update This worked!!!
private void setImage() throws RemoteException{
if(currentBackground != null){
currentBackground.recycle();
}
currentBackground = BitmapFactory.decodeFile(backgroundImageService.getCurrentImageLocation());
view.setBackgroundDrawable(new BitmapDrawable(currentBackground));
}
Thanks
you can use Bitmap.recycle() if you can change your Drawable with Bitmap.
Related
I have spent days trying to work out the cause of this crash in the Google Play Services Saved Game code from a tester's device and have no idea what else to try as it works on all three of my devices. The crash that occurs is:
java.lang.NullPointerException: Must provide a previously opened Snapshot
when I try and call
snapshot.readFully();
even though the snapshot has been opened and return code checked, and checked to see if it is null. Here is the code path leading up to the crash, with non-executed sections removed for brevity:
public void LoadSnapshot()
{
AsyncTask<Void, Void, SNAPSHOT_ASYNC_RESULT> task = new AsyncTask<Void, Void, SNAPSHOT_ASYNC_RESULT>()
{
#Override
protected SNAPSHOT_ASYNC_RESULT doInBackground(Void... params)
{
if (isSignedIn())
{
Snapshots.OpenSnapshotResult result = Games.Snapshots.open(getApiClient(), "MySnapshot", true).await();
int status = result.getStatus().getStatusCode();
DebugLog("Snapshot Load Open result code: " + status);
if (status == GamesStatusCodes.STATUS_SNAPSHOT_CONFLICT)
{
Snapshot snapshot = result.getSnapshot();
Snapshot conflictSnapshot = result.getConflictingSnapshot();
//write both conflicted files so we can merge them
if (snapshot != null && conflictSnapshot != null)
{
byte[] ssdata = snapshot.readFully(); //CRASH HERE!
...
}
...
}
}
}
}
task.execute();
}
I get similar crashes from the same device when simply saving sometimes with .open() followed by .writebytes().
It is making the entire game unstable and I need to get this fixed somehow. Any help or ideas would be much appreciated.
All I can think is that because it's running on a background thread in an AsyncTask something bad has happened in between opening the snapshot and trying to read/write it on this device. According to the tester is crashes 'most' of the time.
I solved this eventually by only allowing one Async operation at a time, as I was previously allowing a concurrent save and load of the same snapshot.
I also wrapped the readFully() inside a try/catch for safety.
I'm working on this as well. I'm looking at the documentation now, and it has this to say about the function: readFully()
Read the contents of a snapshot.
If this snapshot was not opened via open(GoogleApiClient, SnapshotMetadata), or if the contents have already been committed via commitAndClose(GoogleApiClient, Snapshot, SnapshotMetadataChange) this method will throw an exception.
Returns
The bytes of the snapshot contents.
Throws
IOException if reading the snapshot failed.
Are you sure that the snapshot has been opened and committed correctly?
I'm attempting to draw an icon for an achievement using Google Play Game Services API.
However, it is silently failing.
Approach/Issue:
The URI for the image is retrieved successfully, exists and is valid.
I use ImageManager.loadImage to get the image, with an OnImageLoadedListener for callback (com.google.android.gms.common.images.ImageManager).
However OnImageLoadedListener's method, onImageLoaded, is never called.
No error's, no evidence, just completely ignored, I even waited 10 minutes just in case.
Code:
// Get URI [is valid, exists, is of type png, I checked]
Uri uri = getAchievementIconUri(id);
// Use ImageManager to get the icon image
ImageManager.create(context).
loadImage(new ImageManager.OnImageLoadedListener() {
#Override
public void onImageLoaded(Uri u, Drawable d, boolean r) {
/*
* This code is never reached, no call to onImageLoaded is made!
*/
}
}, uri);
It's probably a very late answer, but it might help other people experiencing the same. From the latest google documentation, https://developers.google.com/android/reference/com/google/android/gms/common/images/ImageManager.html#public-methods
Note that you should hold a reference to the listener provided until the callback is complete. For this reason, the use of anonymous implementations is discouraged.
This might explain the behaviour you experienced, as in the first code snippet provided, no reference to the Listener was retained.
Well, for what it matters, I never solved the problem entirely.
It seems that it actually displays the icons occasionally, whenever it feels like it.
I implemented a workaround that loads a compressed, cached version of the image and later replaces it with the ImageManager provided image if it can be bothered doing so.
If anybody works out the correct answer then I will remove this workaround, but until then its here for anybody with the same issue.
Code that loads the local icons:
public Bitmap loadDefaultAchievementIcon(final String id) {
// Get drawable ID for achievement
// iconIdMap is a map of achievement ID strings against their drawable res IDs
int resID = iconIdMap.containsKey(id) ? iconIdMap.get(id) :
// Fallback/unknown icon
R.drawable.ic_action_achievements;
// Load and return bitmap
InputStream is = getResources().openRawResource(resID);
Bitmap bitmap = BitmapFactory.decodeStream(is);
return bitmap;
}
Sometimes my application crashes while trying to open it. As the app hasn't completely started I don't get an error report. I also can't connect my application to the emulator because this behaviour is not reproducable. Sometimes it just crashes once. In other times I can try to open/reopen it as often as I want and it works perfect.
I only use the network-connection (no camera and other stuff). I don't have any services which could crash the application and I tried to reproduce my error by trying to stop the application while it loads something in the background - no success at all.
What do you think could be the reason for crashing? How can I get a log-file, stacktrace something useful for fixing this problem? I simply can't reproduce it so I never see a Logcat-Output when it occurs.
It might be a Fragment-Initializing-Problem but I can't see my mistake. This never occured before and it's just not a common mistake. It might crash only once/twice a week - but it crashes in some point in time...
I've uploaded my project on github but I don't think this is helping somehow.
My main question is: What for opportunities do I have to see what might be the reason behind these random crashes?
Root your phone and install CatLog. When it crashes, open CatLog and save the log so you can view it later.
Or try this if you want to automate it:
Create an exception handler that saves a stack trace to a file.
public class UncaughtExceptionSaver implements UncaughtExceptionHandler{
UncaughtExceptionHandler previousHandler;
Context context;
public UncaughtExceptionSaver (Context context){
this.context = context;
previousHandler= Thread.getUncaughtExceptionHandler();
}
#Override
void uncaughtException(Thread t, Throwable e){
/*Save the stacktrace from the throwable to a
file in your external directory, using context. */
previousHandler.uncaughtException(t,e);
}
}
Then in an Application subclass, call this in the onCreate method:
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionSaver(this));
Spent 3 days on this issue and I'm stumped, could reallly use your help on this.
My app uses a single activity that contains a fragment manager. In its current state, I've designed it to only have a single fragment attached at any one time. I call:
getSupportFragmentManager().beginTransaction().replace(R.id.main_fragment, mCurrent).commit();
to remove the existing fragment and replace it with the new one. The fragments are not being stored anywhere else. (Just mCurrent and the transaction manager which get replaced when the next fragment is opened)
The issue that occurs is not an OutOfMemory exception, but instead the entire app restarts because the device itself runs out of memory. The logs says nothing except stuff like DeadObjectException and:
9-17 11:34:14.742: W/InputDispatcher(341): channel ~ Consumer closed input channel or an error occurred. events=0x9
09-17 11:34:14.742: E/InputDispatcher(341): channel ~ Channel is unrecoverably broken and will be disposed!
These are coming from the device logs and not my app logs. And they don't provide enough information for me to trace what is causing them. The memory from the app is never released and the tablet becomes unusable from that point.
I've used all the tools I know available to analyze what the memory leak would be but nothing stands out. I used MAT (MemoryAnalyzerTool) and the Eclipse DDMS tools to figure out what may be going wrong. MAT reports between 8MB-16MB of total memory in use after I visit many different fragments. I look at the Leaks Report and nothing seems out of the ordinary. About 3MB for Imageviews, 3 MB for Bitmaps, and 8MB for other. In DDMS, the heap says I'm using ~50% of the app's allotted size. When I look at the Settings at the running processes, each Fragment I visit makes the memory amount from my app fluctuate between 30-140MB however the device itself never decreases in memory, hence why the device runs out of memory. Even when the app is completely closed, exited, destroyed, the memory is never released. All 759MB are used even though the sum of all the current running apps is about 200-300MB.
My assumption is that it is either holding on to the fragment itself in memory, or something contained within these fragments even though my app isn't. I call GC after each fragment swap.
I'm using the Samsung Galaxy Tab 2 10.1", but the same issue occurs on Motorola Xoom.
Questions:
Has anyone experienced this kind of behavior?
Can anyone provide me any direction as to other tools to help me research a possible memory leak?
Is there a system process that I can look at to show me in detail how the device memory is being allocated?
Thanks for your time.
Memory leaks in native code can create the symptoms that you're describing: system memory slowly bleeds away while the app's memory footprint (as seen by the JVM) stays more or less constant.
I suggest looking carefully through the memory allocations in your native code and verifying that each one is being cleaned up. This includes calls to malloc, any objects created on the heap (i.e., with "new"), and so forth. There is some tool support for profiling native allocations with DDMS -- see this answer.
Upon further analysis, what I can deduce is that there were three main problems of my memory leaks:
I had initially placed all the UI creation code in the Overridden onStart method because I was unclear of the appropriate location for it (onStart vs onCreateView). I moved all UI code into onCreateView (anything that is related to this.getView() -> use your inflater in the onCreateView). This seemed to eliminate a memory leak that occurred every time I opened and closed the app continuously. Here's a recommendation:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment_one, container, false);
//ALL UI code here using "v"
return v;
}
I was using a ViewPager to house all my fragments (this was because of the specific type of navigation I needed). I switched this to using a custom fragment management solution. I would recommend the use of fragment transaction manager (I originally thought that the fragment manager was causing the leak, but it doesn't appear to be). This wasn't causing a leak, but was eating up a significant amount of memory.
WebViews are a significant cause of memory leaks as well (as its been well documented throughout the internet). I tried using a solution posted which was to wrap the webview in a container and destroy both the webview and its container (Here's the code)
#Override
public void onDestroy()
{
super.onDestroy();
if (mWebContainer != null)
mWebContainer.removeAllViews();
if (mWebView != null)
{
mWebView.loadUrl("about:blank");
mWebView.destroy();
mWebView = null;
}
}
This did not fix my webview issue, but maybe it will fix someone else's out there. I'm continuing to search for the problem. My scenario includes multiple fragments that each have a webview that can open up additional fragments with webviews.
I hope this helps others, I was stuck for over a month debugging all the different scenarios causing leaks as I didn't consider originally that there were many causes. Good luck. Thanks SO community as always.
I found the primary cause of my memory leak. It was around executing a shell command by creating a Process object and opening up input and output streams. I used this to detect rooted devices. I'm not enough of an expert on the Process class to explain why this is causing leaks (I'm going to read up on it now), but if you're using code similar to this I'd be alert to this issue.
public static enum SHELL_COMMAND
{
check_su_binary(new String[] { "/system/xbin/which", "su" }), ;
String[] command;
SHELL_COMMAND(String[] command)
{
this.command = command;
}
}
/**
* #param shellCommand
* #return
*/
public List<String> executeCommand(SHELL_COMMAND shellCommand)
{
//this code was causing my memory leak
try
{
String line = null;
List<String> fullResponse = new ArrayList<String>();
Process localProcess = Runtime.getRuntime().exec(shellCommand.command);
OutputStreamWriter writer = new OutputStreamWriter(localProcess.getOutputStream());
BufferedWriter bufferedWriter = new BufferedWriter(writer);
InputStreamReader reader = new InputStreamReader(localProcess.getInputStream());
BufferedReader in = new BufferedReader(reader);
while ((line = in.readLine()) != null)
{
fullResponse.add(line);
}
}
catch (Exception e)
{
e.printStackTrace();
}
try
{
bufferedWriter.close();
bufferedWriter = null;
writer.close();
writer = null;
in.close();
in = null;
reader.close();
reader = null;
}
catch (IOException e)
{
e.printStackTrace();
}
return fullResponse;
}
I've run into this weird error, where some images get cached as usual and some don't, any idea why?
Both images do get displayed and memory cached just fine, but when offline some display error image.
For example, this works fine:
http://cs4381.vk.me/u73742951/a_58a41ac2.jpg
However, this does not: http://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Android_robot.svg/220px-Android_robot.svg.png
Both work fine displaying and memcaching but the second doesn't get displayed from disk cache, although I think I see it being saved, as app says it has 12kB cache in the system settings
Edit
I checked out a clean copy of Volley and it does the same thing. Its definatelly a bug...
From what Ive found out its that images do get cached, but Bitmap cachedBitmap = mCache.getBitmap(cacheKey); always returns null, so the cache says it doesnt have the bitmaps and then proceedes to download it again, and fail when offline, weird
The reason you're not getting any hits is because the default behavior in Volley for disk caching is dependent on the HTTP headers of the element you're requesting (in your case, an image).
Check the volley logs and see if you get the "cache-hit-expired" message - that means that the image was cached but it's TTL is expired as far as the default disk cache is concerned.
If you want the default settings to work, the images must have a Cache-Control header like max-age=??? where the question marks indicate enough seconds from the time it was downloaded.
If you want to change the default behavior, I'm not sure, but I think you have to edit the code a bit.
Look at the CacheDispatcher class in the Volley source.
Hope that helps.
A quick and dirty way:
private static class NoExpireDiskBasedCache extends DiskBasedCache
{
public NoExpireDiskBasedCache(File rootDirectory, int maxCacheSizeInBytes)
{
super(rootDirectory, maxCacheSizeInBytes);
}
public NoExpireDiskBasedCache(File rootDirectory)
{
super(rootDirectory);
}
#Override
public synchronized void put(String key, Entry entry)
{
if (entry != null)
{
entry.etag = null;
entry.softTtl = Long.MAX_VALUE;
entry.ttl = Long.MAX_VALUE;
}
super.put(key, entry);
}
}