Mapbox-gl-native: Black map when used in another fragment.

Created on 20 Oct 2016  路  8Comments  路  Source: mapbox/mapbox-gl-native

screenshot_20161020-104912

<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"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        android:id="@+id/loaded_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="invisible">

        <com.mapbox.mapboxsdk.maps.MapView
            android:id="@+id/map_view"
            android:layout_weight="1"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            mapbox:style_url="@string/style_mapbox_streets"/>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/places_list"
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

    <RelativeLayout
        android:id="@+id/empty_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible">
        <ImageView
            android:id="@+id/empty_icon"
            android:src="@drawable/sad_face"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:layout_width="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_height="wrap_content" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/empty_icon"
            android:layout_centerVertical="true"
            android:textSize="18sp"
            android:textAlignment="center"
            android:text="There are no places in this team, why not create one?"/>
    </RelativeLayout>

    <ProgressBar
        android:id="@+id/progress_spinner"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:indeterminate="true" />
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_add_white_24dp" />
</RelativeLayout>


public PlacesFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_places, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Log.d("GroupListFragment","View loaded");
        super.showLoading();
        this.initMap(savedInstanceState);
        fab.setOnClickListener(view1 -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            builder.setTitle("Enter Group Title");
            final EditText input = new EditText(getActivity());

            input.setInputType(InputType.TYPE_CLASS_TEXT);
            builder.setView(input);
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    viewModel.createGroup(input.getText().toString());
                }
            });
            builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });

            builder.show();
        });
        getActionBar().setTitle(R.string.fragment_group_list_title);

        Observable<List<PlaceItemViewModel>> placeStream = this.viewModel.getAllGroups().doOnNext(groups -> {
            hideLoading();
            if (groups.isEmpty()) {
                showEmpty();
            }
        });
        placesAdapter = new PlacesAdapter(getActivity(), placeStream);
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
        placesList.setLayoutManager(mLayoutManager);
        placesList.setItemAnimator(new DefaultItemAnimator());
        placesList.setAdapter(placesAdapter);
        this.subscriptions.add(placesAdapter.getElementLongPressed().subscribe(group -> {
            //viewModel.deleteGroup(group);
        }));

        this.subscriptions.add(placesAdapter.getElementPressed().subscribe(group -> {
            /*viewModel.selectGroup(group).subscribe(aVoid -> {
                progressDialog.hide();
                //startActivity(new Intent(getContext(), GroupViewActivity.class));
            });*/

        }));
        hideLoading();
    }

    private void initMap(Bundle savedInstanceState) {
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(mapboxMap -> {

        });
    }

Platform: Android
Mapbox SDK version: com.mapbox.mapboxsdk:mapbox-android-sdk:4.2.0-beta.1@aar

Steps to trigger behavior

  1. I'm not entirely sure how to repeat this behaviour.
    2.
    3.

    Expected behavior

The mapview to draw correctly.

Actual behavior

I have another fragment which uses a mapbox view and it appears to function perfectly, this fragment always suffers from a black box. I can't see anything in the logs to indicate there is any issue.

Android

Most helpful comment

@Almaral-Engineering yes, and please note that MapView#onDestroy needs to be called from Fragment#OnDestroyView

All 8 comments

Thanks for reaching out, couple of follow up questions:

  • is this the full code of PlacesFragment? are you setting an access token?
  • does the logcat show any relevant logs while this occurs?

Hi @tobrun

I set the access token in my application class:

public class TeamTrackApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        RoboGuice.overrideApplicationInjector(this, RoboGuice.newDefaultRoboModule(this), new TeamTrackModule(this));
        MapboxAccountManager.start(this, this.getString(R.string.mapbox_sdk_key));
    }
}

The follow logs are from the fragment:

10-20 11:09:51.343 22907-22907/uk.co.jbrunton.squadcommand D/mbgl: {on.squadcommand}[JNI]: nativeRender
10-20 11:09:51.343 22907-22907/uk.co.jbrunton.squadcommand D/mbgl: {on.squadcommand}[Android]: NativeMapView::activate
10-20 11:09:51.345 22907-22907/uk.co.jbrunton.squadcommand D/mbgl: {on.squadcommand}[Android]: NativeMapView::updateFps()
10-20 11:09:51.346 22907-22907/uk.co.jbrunton.squadcommand D/mbgl: {on.squadcommand}[Android]: NativeMapView::deactivate

You are missing the map lifecycles in PlacesFragment which causes a blank map. Make sure to include:

@Override
  public void onResume() {
    super.onResume();
    mapView.onResume();
  }

  @Override
  public void onPause() {
    super.onPause();
    mapView.onPause();
  }

  @Override
  public void onLowMemory() {
    super.onLowMemory();
    mapView.onLowMemory();
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    mapView.onDestroy();
  }

  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mapView.onSaveInstanceState(outState);
  }

along with the onCreate.

馃憢 Closing this ticket @jjbrunton, if this is still an issue for you, feel free to reach out either on Stack Overflow or through our contact page.

Apologies, I should've mentioned that this resolved the issue. Was a pretty stupid oversight on my part!

I am still having the issue, should I put all in the Activity lifecycle even if I am working with a fragment?

@Almaral-Engineering yes, and please note that MapView#onDestroy needs to be called from Fragment#OnDestroyView

Wow, that worked!, thanks a lot @tobrun, for the help and for answering so fast, for others in the future, what I did was I put all on my fragment where I use the map, and just instead of using onDestroy() I used onDestroyView(), like this:

`
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_map_slide_up, container, false);
mapView = view.findViewById(R.id.map);
mapView.onCreate(savedInstanceState);
....
return view;
}

@Override
public void onStart() {
    super.onStart();
    mapView.onStart();
}

@Override
public void onResume() {
    super.onResume();
    mapView.onResume();
}

@Override
public void onPause() {
    super.onPause();
    mapView.onPause();
}

@Override
public void onStop() {
    super.onStop();
    mapView.onStop();
}

@Override
public void onLowMemory() {
    super.onLowMemory();
    mapView.onLowMemory();
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    mapView.onDestroy();
}

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    mapView.onSaveInstanceState(outState);
}`
Was this page helpful?
0 / 5 - 0 ratings