2

I'm trying to create a map (GoogleMap) inside a layout created in java. I don't understand why i'm getting an error related with an imageView when trying to get an ID from a LinearLayout.

Here's my code:

        LinearLayout mapLayout = new LinearLayout(customToursActivity);
        mapLayout.setId(rootView.generateViewId());
        mapLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 0.5f));
        layout.addView(mapLayout);

        FragmentManager fm = getChildFragmentManager();
        SupportMapFragment supportMapFragment =  SupportMapFragment.newInstance();
        fm.beginTransaction().replace(mapLayout.getId(), supportMapFragment).commit();

Here's the log i got:

01-22 15:04:28.034  19341-19341/abff.googlemapsappteste E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: abff.googlemapsappteste, PID: 19341
    java.lang.ClassCastException: android.widget.ImageView cannot be cast to android.view.ViewGroup
            at android.support.v4.app.BackStackRecord.configureTransitions(BackStackRecord.java:1134)
            at android.support.v4.app.BackStackRecord.beginTransition(BackStackRecord.java:1041)
            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:661)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1501)
            at android.support.v4.app.Fragment.performStart(Fragment.java:1810)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:989)
            at android.support.v4.app.FragmentManagerImpl.performPendingDeferredStart(FragmentManager.java:846)
            at android.support.v4.app.FragmentManagerImpl.startPendingDeferredFragments(FragmentManager.java:1162)
            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1518)
            at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:490)
            at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:1105)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:951)
            at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1473)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at android.support.v7.internal.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:124)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.support.v7.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:444)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5536)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2618)
            at android.view.View.measure(View.java:17637)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2019)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1177)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1383)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1065)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5901)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
            at android.view.Choreographer.doCallbacks(Choreographer.java:580)
            at android.view.Choreographer.doFrame(Choreographer.java:550)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:211)
            at android.app.ActivityThread.main(ActivityThread.java:5389)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)
André Freitas
  • 233
  • 1
  • 5
  • 16
  • I think this line should be changed from `fm.beginTransaction().replace(mapLayout.getId(), supportMapFragment).commit();` to `fm.beginTransaction().replace((ViewGroup)mapLayout.getId(), supportMapFragment).commit();` for proper casting. – gerardnimo Jan 23 '16 at 09:47
  • 1
    I didn't understood why `rootView.generateViewId()` is generating an ID that is already associated with another object, so i replaced this with this aswer (http://stackoverflow.com/a/11615356/3140594) and it worked. – André Freitas Jan 23 '16 at 17:39

1 Answers1

0

I had the exact same problem but required a different fix. Same as you I had a custom View which was programmatically creating a SupportMapFragment. But in my case, this view could be inside a RecyclerView item, so generating a new Id using the method you linked to (where it finds the next available Id using findViewById in a while loop) wouldn't work as the view gets the same Id each time, as its it's calling findViewById within its own child view hierarchy. Same Id is no good because when I do a replace using the fragment manager from within my custom view, it only replaces the first occurrence every time, i.e. the first RecyclerView item.

I found this thread about a bug in Google maps lib where it seems to be using some generated Ids internally which conflict with the first available Ids generated in View.generateViewId(), this led me to try this instead, which fixed the issue:

int newViewId = -1;
int loopCount = 0;

// I tried starting at 70, actual number used internally in Google maps may be lower
while (loopCount < 70) {
    loopCount++;
    if (ApiLevelHelper.SameOrNewer(17)) {
        // using https://gist.github.com/omegasoft7/fdf7225a5b2955a1aba8
        newViewId = ViewHelper.generateViewId();
    } else {
        newViewId = View.generateViewId();
    }
}

FrameLayout mapFrameLayout = new FrameLayout(getContext());
mapFrameLayout.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
mapFrameLayout.setId(newViewId);

FrameLayout pnlMapFragment = (FrameLayout)findViewById(R.id.pnlMapFragment);
pnlMapFragment.addView(mapFrameLayout);

((AppCompatActivity) getContext()).getSupportFragmentManager().beginTransaction()
                    .replace(mapFrameLayout.getId(), this.mapFragment)
                    .commit();

this.mapFragment.getMapAsync(this);
Breeno
  • 2,657
  • 2
  • 26
  • 26