I am trying to inflate a MapFragment within my application but recently, it has started throwing NullPointerException on some devices, mostly Samsung devices. My code in my activity is
if (map == null) {
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
}
And in my XML I define the fragment with
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Does anyone have any reasons why this might be crashing on some devices but not others?
Maybe it is Android fault. In Android Marshmallow 6.0 and higher you need to make requesting for permission, adding it in manifest is not enough.
Related
The mapbox documentation have a lot of confusing deprecated classes and plugins to be used in an Android project.
I'm seeking for the best, latest and most appropriate way to implement custom layout on-top of MapboxView, while keeping in mind to not affect the map's performance, added views to dynamically zoom in and out on map zoom changes.
In short, add a custom view that behave same as the native Mapbox pins, but using a customized Android layout.
Here's an example:
I found this Mapbox documentation that refers to using something like ViewAnnotationManager and PointAnnotationManager but it's written in Kotlin.
Also tried to implement this approach but I couldn't find the above mentioned classes, here's the implemented libraries I have in my Gradle file:
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-markerview-v9:0.4.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v9:0.9.0'
Here's the layout I want to add on top of the map, it's a RippleBackground that contains an ImageView inside of it:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="250dp"
android:layout_height="250dp">
<com.skyfishjy.library.RippleBackground
android:id="#+id/layout_mapview_ripple"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
app:rb_color="#color/primary"
app:rb_radius="28dp"
app:rb_rippleAmount="3"
app:rb_duration="4000"
app:rb_scale="4">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/layout_mapview_user"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/design_white_circle"
android:padding="2dp"
android:scaleType="centerCrop"
android:layout_centerInParent="true"/>
</com.skyfishjy.library.RippleBackground>
</RelativeLayout>
And here's the method I currently have using MarkerView that receives latitude and longitude to add a View on top of the map. But this approach doesn't feel right and the View does not behave as expected when navigating through the map and zooming in/out
public void addUserRippleView(double latitude, double longitude){
View view = LayoutInflater.from(context).inflate(R.layout.layout_mapview_user_ripple, null);
view.setLayoutParams(new ViewGroup.LayoutParams(convertDpToPx(250), convertDpToPx(250)));
// User photo
CircleImageView mUserPhoto = view.findViewById(R.id.layout_mapview_user);
GlideUtil.loadProfilePicture(mSessionManager.getUserPhoto(), context, mUserPhoto);
// Ripple bg
RippleBackground rippleBackground = view.findViewById(R.id.layout_mapview_ripple);
rippleBackground.startRippleAnimation();
MarkerView markerView = new MarkerView(new LatLng(latitude, longitude), view);
mMarkerViewManager.addMarker(markerView);
}
In the XML I have
<androidx.fragment.app.FragmentContainerView
android:id="#+id/identifications_map_view"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent" />
I would like to get the Fragment from the View. The documentation suggests to use
FragmentContainerView fcv = findViewById(R.id.identifications_map_view);
SupportMapFragment smf = fcv.getFragment()
But Android Studio cannot resolve symbol, and if I CTRL+Click the "FragmentContainerView" it doesn't show getFragment() when i search with CTRL+F.
I know there is another way to get the Fragment but I was wondering why I can't do it this way. I guess there is some problem with the version, because I seem to have an older version of the class than the documentation's, for example there is also an extra constructor that uses the FragmentManager, nowhere to be found in the documentation.
Could it even be minimum API problem? I have 24.
Thanks.
It has been added from 1.4.0-alpha01 (https://developer.android.com/jetpack/androidx/releases/fragment#1.4.0-alpha01)
If you are on a lower version it won't be there.
When you use androidx.fragment.app.Fragment try this:
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragment_container"
android:name="com.example.YourFragment"
android:tag="custom_tag"
tools:layout="#layout/your_fragment_layout" />
And get this fragment instance by:
childFragmentManager.findFragmentByTag("custom_tag")
UPD: In some cases it doesn't works. I don't know why. Try this:
binding.fragmentContainer.getFragment<YourFragment>()
As stated by Sam, the method getFragment() wasn't added to FragmentContainerView until 1.4.0 alpha versions.
However, as per documentation:
This method grabs the Fragment whose view was most recently added to the container. This may used as an alternative to calling FragmentManager.findFragmentById and passing in the FragmentContainerView's id.
Therefore, the alternative here is to simply do it as you would with the <fragment /> tag:
SupportMapFragment smf = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.identifications_map_view);
And things would work just as well.
I think you might be right about the minimum api.
According to the docs to use the androidx package you need to be api 28 or higher
https://developer.android.com/jetpack/androidx
I'm working on google maps using fragment. API version is 23.
mapFragment = FragmentManager.FindFragmentById<MapFragment>(Resource.Id.mapFragment);
The above code is highlighted that it's obsolete.
AXML file
<fragment
android:layout_width="match_parent"
android:layout_height="200dp"
class="com.google.android.gms.maps.MapFragment"
android:id="#+id/mapFragment"/>
Any idea on another way of implementing?
Well in simple terms Android recently marked all the old Fragment classes and its other supporting classes as obsolete.
Now it is adviced that you use the Support library Fragment, Fragment Manager.
How do you do that in Xamarin!
Inherit your fragment class from android.support.v4.app.Fragment instead of android.app.Fragment
Use SupportFragmentManager instead of FragmentManager which is well explained in this Java Guide
Change your AXML with:
<fragment
android:layout_width="match_parent"
android:layout_height="200dp"
class="com.google.android.gms.maps.SupportMapFragment"
android:id="#+id/mapFragment"/>
and your code with:
SupportMapFragment _mapFragment = (SupportMapFragment)SupportFragmentManager.FindFragmentByTag("mapFragment");
if (_mapFragment == null)
{
GoogleMapOptions mapOptions = new GoogleMapOptions()
.InvokeRotateGesturesEnabled(true)
.InvokeScrollGesturesEnabled(true)
.InvokeCompassEnabled(true)
.InvokeAmbientEnabled(true)
.InvokeMapType(GoogleMap.MapTypeNormal)
.InvokeZoomControlsEnabled(true)
.InvokeCompassEnabled(true);
_mapFragment = SupportMapFragment.NewInstance(mapOptions);
Android.Support.V4.App.FragmentTransaction fragTx = SupportFragmentManager.BeginTransaction();
fragTx.Add(Resource.Id.map, _mapFragment, "map");
fragTx.Commit();
_mapFragment.GetMapAsync(this);
OK I've read most of available answer on similar questions but nothing fixed my problem
gradle classpath 'com.android.tools.build:gradle:2.1.2'
android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 24
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
compile 'com.android.support:recyclerview-v7:24.1.1'
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.android.support:cardview-v7:24.1.1'
compile 'com.android.support:support-v4:24.1.1'
compile 'com.android.support:design:24.1.1'
}
activity.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/ScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ViewItem"
tools:ignore="MissingPrefix">
...
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_gravity="center_vertical"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="10dp"
android:foregroundGravity="center_vertical|center|center_horizontal"
app:srcCompat="#drawable/ic_car" />
...
</ScrollView>
vector ic_car.xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#5c5c5c"
android:pathData="M18.92 6.01C18.72 5.42 18.16 5 17.5 5h-11c-.66 0-1.21 .42 -1.42 1.01L3 12v8c0
.55 .45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55 .45 1 1 1h1c.55 0 1-.45
1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5 .67 1.5
1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5 .67 1.5
1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z" />
<path android:pathData="M0 0h24v24H0z" />
</vector>
my activity class extends AppCompatActivity and all android:src tags are changed to app:srcCompat but still I see Invalid drawable tag vector error on the minSdkVersion which is set to 16.
In my case, the crash happened due to using Resources.getDrawable(int) to get the vector drawable on pre-lollipop devices. I was trying to create a drawable to pass into
ImageView.setImageDrawable(Drawable).
Google Blog Post for Android Support Library 23.2:
As of Android Support Library 23.3.0, support vector drawables can
only be loaded via app:srcCompat or setImageResource().
Solution: Use VectorDrawableCompat.create(Resources, int, Theme) to create the drawable.
You can also use ImageView.setImageResource(int) however this will read/decode the bitmap on the UI thread.
Truth is, looking at your code, it should work in any version of the library, as you are using only the srcCompat attribute.
One issue I suspect, is that your vector is in a drawable-21 folder, while in the regular Drawable folder you have single file that references these Drawables. This was a method done in early versions of the library, but does not work anymore due to changes below. Just move the actual vector file to the Drawable folder.
We have had sometimes similar issues that were solved by changing the ImageView to an AppCompatImageView. Even though the library is supposed to do this automatically, it seems that sometimes it doesn't.
It is still possible that the code is breaking if your vector is part of a compound image, for example a layered image. Or it's breaking somewhere else for which you have not posted the code, for example if you are setting a vector as the leftImage on an ImageButton. These functionalities have been removed in 23.3, as #Zeke has answered. Nonetheless, it was returned in 23.4, made usable by adding the following to your activity
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
They still warn you it can cause memory leaks. See https://medium.com/#chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88#.s48hqaw1u, though for minimal use it shouldn't be an issue.
A simple workaround would be to create the Drawable and set it in code. Something like this;
Drawable icon = AppCompatDrawableManager.get().getDrawable(context, resVectorID);
// Set it for example as a left image of button
button.setCompoundDrawablesWithIntrinsicBounds( icon, null, null, null );
I have not tested this, and have no ideas if this causes memory issues or not. Would love it if someone can follow up.
Problem got solved itself after updating to Android studio 2.2
I did like this:
public static final Drawable getMyDrawable(Context context, int id) {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
return ContextCompat.getDrawable(context, id);
} else {
return VectorDrawableCompat.create(context.getResources(), id, context.getTheme());
}
}
The following classes could not be instantiated:
- com.amazon.device.ads.AdLayout (Open Class, Show Error Log)
See the Error Log (Window > Show View) for more details.
Tip: Use View.isInEditMode() in your custom views to skip code when shown in Eclipse
java.lang.NoClassDefFoundError: Could not initialize class android.os.Environment
at com.amazon.device.ads.DebugProperties.readDebugProperties(DebugProperties.java:75)
at com.amazon.device.ads.InternalAdRegistration.<init>(InternalAdRegistration.java:52)
at com.amazon.device.ads.InternalAdRegistration.getInstance(InternalAdRegistration.java:64)
at com.amazon.device.ads.AdLayout.initialize(AdLayout.java:185)
at com.amazon.device.ads.AdLayout.initialize(AdLayout.java:176)
at com.amazon.device.ads.AdLayout.<init>(AdLayout.java:120)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0( at sun.reflect.NativeConstructorAccessorImpl.newInstance( at sun.reflect.DelegatingConstructorAccessorImpl.newInstance( at java.lang.reflect.Constructor.newInstance( at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.instantiateClass(ProjectCallback.java:422)
at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.loadView(ProjectCallback.java:179)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:207)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:135)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:755)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:727)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:373)
My main.xml looks like this
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:Amazon="http://schemas.android.com/apk/lib/com.amazon.device.ads"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="top|center_horizontal" >
<com.amazon.device.ads.AdLayout
android:id="#+id/myAdView"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
My MainActivity.java is this
import com.amazon.device.ads.AdLayout;
import com.amazon.device.ads.AdRegistration;
import com.amazon.device.ads.AdTargetingOptions;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
preferences = PreferenceManager.getDefaultSharedPreferences(this);
int defaultValue = R.drawable.blue;
int themedefault = ThemeChanger.THEME_BLUE;
appliedtheme = preferences.getInt("mytheme", themedefault);
ThemeChanger.onActivityCreateSetTheme(this, appliedtheme);
setContentView(R.layout.main);
AdRegistration.setAppKey("Application_Key");
this.adView = (AdLayout) findViewById(R.id.myAdView);
this.adView.loadAd(new AdTargetingOptions());
button1 = preferences.getInt("DigitButtonStyle", defaultValue);
buttonmadd = preferences.getInt("MemoryButtonStyle", defaultValue);
buttoncos = preferences.getInt("FunctionButtonStyle", defaultValue);
I had the same issue and followed Amazon developer guide. To solve this issue, just copy amazon library and paste it in your libs folder and than run.
It's a known issue in Eclipse ADT plugin, even if you use View.isInEditMode(), in some cases, it crashes in recent API versions (higher than 18). It's fixed in Android Studio.
If you want to see Layout Preview, you can try with different API version lower than 19.
Check the screenshot. It's using API 18. (Red box is Amazon AdLayout)