Moving MapFragment (SurfaceView) causes black background flickering

后端 未结 16 1387
误落风尘
误落风尘 2020-12-04 09:32

I\'m trying to implement new Android Google Maps API (v2). However it doesn\'t seem to go well with SlidingMenu. As you may know, MapFragment implementation is

相关标签:
16条回答
  • 2020-12-04 09:49

    Here's a crazy idea, don't move the MapView ;-)

    That is, create a MapView full screen width behind your app in a FrameLayout. Then lay your views on top, and punch a hole through to the MapView in the position you need to display it. When moving you'll need to update the map position to stay in sync so the user keeps seeing the same section of the map, but that should update better than moving a surface view around.

    0 讨论(0)
  • 2020-12-04 09:50

    I had the same problem and used a workaround based on changing the "Visibility".

    private GoogleMap mMap;
    private SupportMapFragment mMapFragment;
    
    mMapFragment = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.mapFragment));
    mMap = mMapFragment.getMap();
    
    //Change the visibility to 'INVISIBLE' before the animation to go to another fragment.
    mMapFragment.getView().setVisibility(View.INVISIBLE);
    
    //Change the visibility to 'VISIBLE' after coming back to the original fragment that has map fragment.
    mMapFragment.getView().setVisibility(View.VISIBLE);
    
    0 讨论(0)
  • 2020-12-04 09:51

    Of course the proper solution will be for Google to fix the problem (see Android Maps V2 issue 4639: http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639).

    However, one of my coworkers suggested simply extending the map beyond its container. If we extend the map fragment beyond the visible region of its container, like so:

    android:layout_marginLeft="-40dp"
    android:layout_marginRight="-40dp"
    

    we can reduce/eliminate the flickering. Newer devices (e.g. Galaxy Nexus) show no flickering after this hack, and older devices (e.g. LG Optimus V) show reduced flickering. We have to extend margins on both sides so that info windows are centered when they're selected.


    Update: This issue was fixed by Google on Aug. 28, but I'm guessing it still has to be rolled into a release.

    0 讨论(0)
  • 2020-12-04 09:52

    Here's a very simple workaround I used to get rid of the flashing in a ViewPager. I would imagine the same will hold true for any Fragment or other dynamically added MapView.

    The problem doesn't really seem to be the MapView itself, but the resources needed to run the MapView. These resources are only loaded the first time you fire up a MapView in your activity and re-used for each subsequent MapView, as you would expect. This loading of resources is what causes the screen to flash.

    So to remove the flashing, I just included another MapView in the layout of my Activity (location in the activity is irrelevant). As soon as the Activity has loaded, I just set the Visibility of the extra MapView to GONE. This means all the resources needed for your MapView are ready for when you fire up any of your Fragments using MapViews with no lag, no flashing, all happiness.

    This is of course a workaround and not a real 'solution' to the underlying problem but it will resolve the side effects.

    So to cover off the code used for completeness:

    Randomly (but cleanly) placed in my Activity Layout:

    <com.google.android.gms.maps.MapView
            android:id="@+id/flash_map"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    

    Then in my Activity Class

    private MapView flashMap;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
                // Code omitted
    
        try {
            MapsInitializer.initialize(this);
        } catch (GooglePlayServicesNotAvailableException e) {
            e.printStackTrace();
        }
        flashMap = (MapView)findViewById(R.id.flash_map);
        flashMap.onCreate(savedInstanceState);
    }
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
            flashMap.onSaveInstanceState(outState);
    }
    
    @Override
    public void onResume() {
        super.onResume();
        flashMap.onResume();
        flashMap.setVisibility(View.GONE); // Just like it was never there...
    }
    
    @Override
    public void onPause() {
        flashMap.onPause();
        super.onPause();
    }
    
    @Override
    public void onDestroy() {
        flashMap.onDestroy();
        super.onDestroy();
    }
    
    @Override
    public void onLowMemory() {
        super.onLowMemory();
        flashMap.onLowMemory();
    }
    
    0 讨论(0)
  • 2020-12-04 09:55

    Well, Quoting Dianne Hackborn (an Android framework engineer)

    The surface view is actually BEHIND your window, and a hole punched in the window for you to see it. You thus can put things on top of it in your window, but nothing in your window can appear behind it. Original post

    This architecture is part of why you see these flickers.

    Some flickering sometimes appear due to double buffers: Android coding blog explains further.

    You can also try and subclass the SurfaceView to try and draw the background differently. I haven't seen an example of this that doesn't change the z-index to be that of the top. Check out this SO post

    Otherwise, I recommend only getting the SurfaceHolder after your view is focused (try and make a temporary view until then) and removing the SurfaceView whilst not in focus and on screen.

    0 讨论(0)
  • 2020-12-04 09:55

    Another alternative solution is to use the new GoogleMap.snapshot() function, and using a screenshot of the map instead; as described here.

    0 讨论(0)
提交回复
热议问题