I'm struggling with a memory leak issue at Google Maps Android API v2. The heap usage increases by about 85KB every time my view becomes visible again after:
Phone screen turns off (eg after pressing the power button).
The user exits the app pressing the Home button.
The app eventually crashes with an OutOfMemory exception. The leak does NOT occur on screen rotate, or when exiting by "back" button. Any ideas about a workaround or the reason behind this problem?
My code:
public class LeakActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leak);
}
}
and the XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/map_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</RelativeLayout>
This might be related to this open issue in the Maps API:
Issue 4766 - Bug: Android Maps API v2 leaks huge amounts of memory
Use DDMS' "Dump HPROF" tool to dump a hprof file, convert it with hprof-conv and use MAT to examine the leak. If it's in Google Maps API, please post an apk (or better simple test code) to the open issue and include the hprof file.
If it is the same bug I am experiencing, it might only happen on Android 2.x, please check that too.
I tried to use System.gc() and map.clear() before the map is initialized.
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) == ConnectionResult.SUCCESS) {
System.gc();
getMap().clear();
setupmap();
}
}
#Override
public void onLowMemory() {
super.onLowMemory();
System.gc();
}
Related
Do you know good practices to avoid memory leaks ?
I am currently working on an app which has few memory leaks, that I struggle to fix, mainly because I don't know the habits that I need to take to be able to avoid them.
For instance, at the moment I get this issue
Fatal Exception: java.lang.OutOfMemoryError
Failed to allocate a 1627572 byte allocation with 1293760 free bytes and 1263KB until OOM
Raw Text
dalvik.system.VMRuntime.newNonMovableArray (VMRuntime.java)
android.view.LayoutInflater.inflate (LayoutInflater.java:429)
com.XX.Dialog.PopupDialog.onCreateView (PopupDialog.java:50)
Which comes from the inflater.inflate(R.layout.dialog_popup, container, false); in the onCreateView !
Here is the DialogFragment concerned :
public final class PopupDialog extends DialogFragment {
public PopupDialog()
{
}
#Override
public void onSaveInstanceState(Bundle outState) {
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
View view = inflater.inflate(R.layout.dialog_popup, container, false);
return view;
}
The layout is quite long, but basically it got 5 ImageViews . Here is an sample :
<ImageView
android:layout_width="match_parent"
android:layout_height="80dp"
android:id="#+id/popup_top_bg_iv"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="false"
android:layout_alignParentStart="false"
android:src="#drawable/popup_top_bg"
android:scaleType="fitXY"
android:background="#color/transparent" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/popup_top_bg_iv"
android:background="#ffffff"
android:layout_alignBottom="#+id/popup_bottom_ll" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/popup_top_iv"
android:src="#drawable/popup_0_top"
android:scaleType="fitCenter"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp" />
....
So .... I was wondering if you know :
1. What could lead to this memory leak error from this dialogFragment ?
2. Any good practices in android to avoid memory leaks ?
For instance for that file, should I call
imageView.setImageDrawable(null);
On every Imageview when the popup is closed / Activity is closed (R.drawable.* ) ? Or just when I load an image from an URL (with Glide for instance) dynamically ?
Should I always resize an image to the dimension of my Imageview ?
What exactly do I need to clean after the Fragment/Activity is closed ?
What do you think ?
After a bit of digging I came with these solutions :
you can use Leak canary to track your memory leak (https://github.com/square/leakcanary)
Or the Memory monitor of Android studio : https://developer.android.com/studio/profile/am-memory.html
Use a library to load your images such as Picasso or Glide. Personally I prefer Glide.
https://medium.com/#multidots/glide-vs-picasso-930eed42b81d
Never keep references of Activity of context in static. NEVER!
Otherwise your references might still be there even if you need it.
Avoid keeping references of ImageViews. Recycle / Clear the bitmap inside when your destroy the view.
If you need to have a reference of the context, please use context.getApplicationContext();
Don't use context.getApplicationContext(); for LayoutInflater.from(context); but directly the context.
(in case if you need to inflate a view or need a context for something).
If you use the context.getApplicationContext() it can lead to some design issues if you create views dynamically.
If you get some OutOfMemory error, think to compress your images ! It actually saves me lot of OutOfMemory error. You can use https://tinypng.com/.
Don't put by default your images into the folder drawable-xhdpi but drawable-mdpi instead as drawable-mdpi is the default one.
So for my issue I just need to compress the images and put them back in the drawable-mdpi folder ! All good now !
I'm currently working on Android and have started with Google Maps V2 API.
As I have finished going through all their setup guide the map worked and I was able to see the continents. Only problem is that when I zoom in, the map stays the same I just get less pixels untill eventually I get gray squares - as if it has loaded the map but not entirely. I'd been looking around for someone with a problem like mine and couldn't find any.
Any assistance will be appreciated.
My code:
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment"/>
public class myMapActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
}
More information:
I had added:
GoogleMap map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMap();
map.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
and gotten gray squares without map at all. hope it helps identify the problem Thank you in advance.
As recommended I had uninstalled which probably removed previous save of the map.
After reinstalling the app works fine.
I am working on a project using Google Maps v2 for Android and I am getting a NoSuchFieldError while instantiating the Google map fragment on a rooted HTC Desire HD.
Afaik, the issue should not be caused by Google Play Services not being installed on the device (event though they are and other applications using Google Maps v2 are working).
I have tried making a check to see if Google Play Services library is installed on the device (by calling GooglePlayServicesUtil.isGooglePlayServicesAvailable) prior to setting the Activity's content view.
Furthermore, the application runs on other Android phones and the map fragment is successfully inflated.
At the moment I suspect that this issue is caused by my Android project setup in Eclipse, as the Google Play Services library project seems not to be included along with my project during packaging or deployment.
Has anyone had and solved this issue with Google Maps working only on some devices and throwing a NoSuchFieldError exception on others? If so, what can I do to solve this?
If you need more information such as project setup and/or code, please leave a comment.
Thank you!
This is the stack trace report from ACRA in JSON format:
{ CUSTOM_DATA: '',
STACK_TRACE: 'java.lang.NoSuchFieldError: com.google.android.gms.R$string.common_google_play_services_unsupported_text\n\tat com.google.android.gms.common.GooglePlayServicesUtil.b(Unknown Source)\n\tat com.google.android.gms.internal.bb.a(Unknown Source)\n\tat com.google.android.gms.internal.bb.onCreateView(Unknown Source)\n\tat com.google.android.gms.maps.SupportMapFragment.onCreateView(Unknown Source)\n\tat android.support.v4.app.Fragment.performCreateView(Fragment.java:1460)\n\tat android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:884)\n\tat android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1066)\n\tat android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1168)\n\tat android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:280)\n\tat android.view.LayoutInflater.createViewFromTag(LayoutInflater.java)\n\tat android.view.LayoutInflater.rInflate(LayoutInflater.java)\n\tat android.view.LayoutInflater.inflate(LayoutInflater.java)\n\tat android.view.LayoutInflater.inflate(LayoutInflater.java)\n\tat android.view.LayoutInflater.inflate(LayoutInflater.java)\n\tat com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java)\n\tat android.app.Activity.setContentView(Activity.java)\n\tat ro.myapp.app.activities.MapActivity.onCreate(MapActivity.java:62)\n\tat android.app.Activity.performCreate(Activity.java)\n\tat android.app.Instrumentation.callActivityOnCreate(Instrumentation.java)\n\tat android.app.ActivityThread.performLaunchActivity(ActivityThread.java)\n\tat android.app.ActivityThread.handleLaunchActivity(ActivityThread.java)\n\tat android.app.ActivityThread.access$600(ActivityThread.java)\n\tat android.app.ActivityThread$H.handleMessage(ActivityThread.java)\n\tat android.os.Handler.dispatchMessage(Handler.java)\n\tat android.os.Looper.loop(Looper.java)\n\tat android.app.ActivityThread.main(ActivityThread.java)\n\tat java.lang.reflect.Method.invokeNative(Native Method)\n\tat java.lang.reflect.Method.invoke(Method.java)\n\tat com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)\n\tat com.android.internal.os.ZygoteInit.main(ZygoteInit.java)\n\tat dalvik.system.NativeStart.main(Native Method)\n',
PHONE_MODEL: 'HTC Desire HD',
ANDROID_VERSION: '4.0.4' }
This is my onCreate method throwing the exception:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
checkForPlayServices();
setContentView(R.layout.activity_map);
mapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
map = mapFragment.getMap();
map.setMyLocationEnabled(true);
map.setInfoWindowAdapter(this);
map.setOnInfoWindowClickListener(this);
}
Contents of activity_map.xml layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapActivity" >
<ro.myapp.app.views.actionbar.ActionbarMap
android:id="#+id/actionBar"
android:layout_width="match_parent"
android:layout_height="#dimen/myapp_actionbar_height" />
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="#id/actionBar"
class="com.google.android.gms.maps.SupportMapFragment" />
</RelativeLayout>
java.lang.NoSuchFieldError: com.google.android.gms.R$string.common_google_play_services_unsupported_text
says exactly what is the problem.
In values/strings.xml there is no
<string name="common_google_play_services_unsupported_text">...</string>
defined.
I see this value defined in my google-play-services_lib/res, so you may want to check if you correctly added this library project to your workspace. Seems like you have forgot to update strings.xml when updating library.
Ok so I changed my answer I found out there is a way to find out if there is anything overriding your libs.... You are using the Location Objects somewhere so add this bit of code and debug it when running one of those devices..... The location object should be in your location listener.
location.getClass().getProtectionDomain().getCodeSource().getLocation() ;
Want to develop a QR code reader.. which will customized for my application. after a lot of search i found a link http://www.androidaz.com/development/zxing-qr-reader-direct-integration this tutorial demonstrate what i exactly want. but when i import it and then run this app i notice that its camera is in 90 degree angle when i rotate device. what is the problem i can not realize. my main.xml is
<FrameLayout
android:layout_width="200dip"
android:layout_height="200dip"
android:layout_gravity="center_horizontal">
<include layout="#layout/capture"/>
</FrameLayout>
my mainactivity file is:
public class ScannerActivity extends CaptureActivity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qrcode);
}
#Override
public void handleDecode(Result rawResult, Bitmap barcode)
{
Toast.makeText(this.getApplicationContext(), "Scanned code " + rawResult.getText(), Toast.LENGTH_LONG).show();
}
}
menifest file with permission :
<uses-permissionandroid:name="android.permission.CAMERA"/>
<uses-permissionandroid:name="android.permission.INTERNET"/>
<uses-permissionandroid:name="android.permission.VIBRATE"/>
<uses-permissionandroid:name="android.permission.FLASHLIGHT"/>
<uses-permissionandroid:name="android.permission.READ_CONTACTS"/>
<uses-permissionandroid:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permissionandroid:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE"/>
it can read QR code fine. only problem camera caused abnormal behavior when rotating..
Thanks in advanced.
Maybe what you would like to do is here:
android-zxinglib
An android library project of zxing BarcodeScanner
https://code.google.com/p/android-zxinglib/
Download the project and look these files:
AndroidManifest.xml
capture.xml
Go into your manifest and change the orientation to landscape. Portrait caused the same problem for me, and landscape looked a lot better.
public class Map extends MapActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
MapView mapView = (MapView) findViewById(R.id.myMapView1);
mapView.getController().animateTo(srcGeoPoint);
mapView.getController().setZoom(15);
}
the map.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.google.android.maps.MapView
android:id="#+id/myMapView1"
android:layout_width="fill_parent"
android:layout_x="0px"
android:enabled="true"
android:clickable="true"
android:apiKey="Obtained Key here" android:layout_y="105px" android:layout_height="fill_parent">
</com.google.android.maps.MapView>
</LinearLayout>
I check the log there's only one red mark, Failed to find provider info for com.google.settings. everything else seems to be fine. I am wondering why the map is empty looking?
The MapView is empty when your Maps API key is expired or not matching with your debug signature key.
Try to generate a new one.
Inside every MapActivity, the isRouteDisplayed() method is required,
so override this method:
#Override protected boolean isRouteDisplayed() {
return false; }
This method is required for some accounting from the Maps service to
see if you're currently displaying any route information. In this
case, you're not, so return false.
source: http://developer.android.com/resources/tutorials/views/hello-mapview.html
Additional the android:layout_x="0px looks a little bit dodgy to me. I think it's only used in AbsoluteLayouts so deleting it should not harm.
Please check logs whether you are not getting "unable to authenticate error from google server". If yes there is issue with map key.
Map key should be generate on same system where you are running application.
Also check whether you have google play account signed and location setting is enabled.
please check here for more details:
https://developers.google.com/maps/documentation/android/start