Android ActionBar turns black when loading Fragmen

2019-05-11 08:14发布

问题:

I have Activity where I made DrawerLayout where I have 5 entries in side menu and each menu entry is loading its fragment (below in code you will see only 3 Fragments, that's because last two menu entries are dummy for now). On that Activity I set my custom ActionBar. Activity and its onCreate method look something like this:

public class ActivityOffline extends ActionBarActivity implements OnPreferencesFragmentListener {
    final String[] fragments = { array with fragments path };

    private String[] drawerListViewItems;
    private DrawerLayout drawerLayout;
    private ListView drawerListView;
    private ActionBarDrawerToggle actionBarDrawerToggle;

    private Fragment mF1
    private Fragment mF2
    private Fragment mF3

    @SuppressLint("InlinedApi")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
        setContentView(R.layout.activity_offline);

        mF1 = Fragment.instantiate(ActivityOffline.this, fragments[0]);
        mF2 = Fragment.instantiate(ActivityOffline.this, fragments[1]);
        mF3 = Fragment.instantiate(ActivityOffline.this, fragments[2]);

        LayoutInflater inflator = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = inflator.inflate(R.layout.action_bar_custom, null);

        final ActionBar actionBar = getSupportActionBar();

        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setCustomView(v, new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.WRAP_CONTENT, Gravity.CENTER_VERTICAL
                | Gravity.FILL_HORIZONTAL));

        // Get list items from strings.xml
        drawerListViewItems = getResources().getStringArray(R.array.items);

        // Get ListView defined in activity_main.xml
        drawerListView = (ListView)findViewById(R.id.left_drawer);

        // App Icon
        drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);

        // Set the adapter for the list view
        drawerListView.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_listview_item, drawerListViewItems));

        FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
        tx.replace(R.id.content_frame, mF1);
        tx.commit();

        // Create ActionBarDrawerToggle
        actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close);

        // Set actionBarDrawerToggle as the DrawerListener
        drawerLayout.setDrawerListener(actionBarDrawerToggle);

        // Еnable and show "up" arrow
        actionBar.setDisplayHomeAsUpEnabled(true);

        // Јust styling option
        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        drawerListView.setOnItemClickListener(new DrawerItemClickListener());
    }
    }

When I am switching between menu items, I am always replacing fragments like this:

private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(@SuppressWarnings("rawtypes") AdapterView parent, View view, final int position, long id) {
            drawerLayout.setDrawerListener(new DrawerLayout.SimpleDrawerListener() {
                @Override
                public void onDrawerClosed(View drawerView) {
                    super.onDrawerClosed(drawerView);

                    if (position < 3) {
                        FragmentTransaction tx = getSupportFragmentManager().beginTransaction();

                        switch (position) {
                        case 0:
                            tx.replace(R.id.content_frame, mF1);
                            break;
                        case 1:
                            tx.replace(R.id.content_frame, mF2);
                            break;
                        case 2:
                            tx.replace(R.id.content_frame, mF3);
                            break;
                        default:
                            tx.replace(R.id.content_frame, mF1);
                            break;
                        }

                        tx.commit();
                    }
                }
            });

            drawerLayout.closeDrawer(drawerListView);
        }
    }

So, my Fragment which has Google Map is mF2. It's implementation and layout file are below:

Implementation:

public class FragmentRouteView extends Fragment {
    static final LatLng MY_LOCATION = new LatLng(54.002858, 7.956872);

    private MapView mMapView;
    private GoogleMap mGoogleMap;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_route_view, container, false);
        mMapView = (MapView)v.findViewById(R.id.mapView);
        mMapView.onCreate(savedInstanceState);
        mMapView.onResume();

        try {
            MapsInitializer.initialize(getActivity());
        }
        catch (GooglePlayServicesNotAvailableException e) {
            e.printStackTrace();
        }

        mGoogleMap = mMapView.getMap();

        // Move the camera instantly to start point with a zoom of 15.
        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(MY_LOCATION, 15));

        // Zoom in, animating the camera.
        mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);

        return v;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

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

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

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

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

Layout file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black" >

    <com.google.android.gms.maps.MapView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapView"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

If you are asking why do I have this View in layout file - don't. It solves some problem for me and has nothing to do with issue I currently have.

Anyhow. After this intro, here's the problem:

When I first time start my activity which displays these fragments and I navigate first time to mF2 (which has Google Map), I see map, but my ActionBar is totally black. No title, no side button which displays drawer menu. Plus, I don't see + and - signs on Google Map.

Here's preview:

But, although action bar is totally black, if I press on place where menu button should be, menu displays and menu button and title are displayed again.

Like this:

And afterwards, I don't encounter this problem ever while activity is alive.

Everything's then fine like displayed below:

When activity is destroyed and I start it again, I encounter this problem again when I navigate first time to mF2 with Google Map.

This doesn't happen on devices which have Android 4.x.x. It only happens on devices with Android 2.x.x.

Any idea what's causing this?

To prevent any unrelated counter questions:

  • Yes, I am using support libraries in right way
  • Yes, I have set Google Maps API V2 key properly
  • Yes, I am using debug key when I am starting app on device from Eclipse
  • Why do I use RelativeLayout in my Maps fragment layout and not only com.google.android.gms.maps.MapView? - I needed that magic View for some reason, and if try with com.google.android.gms.maps.MapView it also makes no difference, same thing happens.

Many thanks in advance.

[edit #1]: There's a case when this problem is gone:

I forgot to add this:

If I comment out these lines from my Maps Fragment implementation:

// Move the camera instantly to start point with a zoom of 15.
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(MY_LOCATION, 15));

// Zoom in, animating the camera.
mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);

I see Google Map centered on (0,0) coordinates and ActionBar IS DISPLAYED CORRECTLY. So, it looks like that this problem occurs when I am doing something extra with map (zooming, positioning, drawing markers, etc).

回答1:

There have been some known issues ([1], [2], [3]) with rendering UI items on top of the Maps API v2 view that produce a black box in the UI item.

Here's the latest update from gmaps-api-issues issue #4659, as of Aug. 27th 2013:

We just pushed an update that changes the base view of the map to a TextureView on Jelly Bean 4.1+ (API 16+) devices. This should resolve several issues, including black rectangles when a map view is moved on the screen.

TextureView was introduced in Ice Cream Sandwich, but we found many ICS devices with driver issues and/or buggy implementations of TextureView. Rendering artifacts cannot be resolved for those devices, or any pre-ICS devices.

To ensure your map can use TextureView, the view needs to be hardware accelerated. This can be done on the Application, Activity or Window level. See Android’s documentation for information on this: http://developer.android.com/guide/topics/graphics/hardware-accel.html

There are some reported workarounds in comments on that issue that you may want to try, but it appears that the underlying problem on pre-ICS devices can't be resolved.