【问题标题】:Memory Leak on MapView with Overlays (Osmdroid)MapView 上的内存泄漏与覆盖 (Osmdroid)
【发布时间】:2021-02-11 15:12:00
【问题描述】:

我的应用程序“传感器记录”中存在内存泄漏问题。它有几个活动,其中一个是地图活动(基于 osmdroid 6.1.8),其中我显示了一个背景 MAPNIK 和一些 GroundOverlay s 包含天气图。

当我在活动之间切换时 - 或者当我将设备从纵向旋转到横向并返回时 - 每次重新构建地图时,内存消耗都会增加。迟早(取决于设备内存)我会收到 OutOfMemoryError。

有关更详细的信息,这里是 Java 源代码的摘录,已清理了它周围的所有垃圾。 地图活动:

@Override
public void onCreate (Bundle savedInstanceState)
{
    .
    .
    .
    // basic map
    MapView mapView = (MapView) findViewById(R.id.mapview);
    mapView.setTileSource(TileSourceFactory.MAPNIK);

    // overlays
    mapView.getOverlays().clear();
    WeatherOverlay weatherOverlay = new WeatherOverlay(this, mapView, wdStack);
    mapView.getOverlays().add(0, weatherOverlay);
    .
    .
    .
}  // onCreate

和类 WeatherOverlay:

public class WeatherOverlay extends Overlay implements Runnable
{
    private GroundOverlay[] groundOverlay;

    private ConnectivityManager connectivityManager;

    private Context      context;
    private MapView      mapView;
    private WeatherStack wdStack;


    // constructor
    public WeatherOverlay(Context context, MapView mapView, WeatherStack wdStack)
    {
        super();

        this.context     = context;
        this.mapView     = mapView;
        this.wdStack     = wdStack;

        groundOverlay = new GroundOverlay[wdStack.getSize()];

        for (int index = 0; index < wdStack.getSize(); index++)
        {
            groundOverlay[index] = new GroundOverlay();
    
            groundOverlay[index].setPosition(
                    wdStack.getEntry(index).northWest,
                    wdStack.getEntry(index).southEast);
    
            mapView.getOverlays().add(0, groundOverlay[index]);
        }

        connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

    }  // constructor


    @Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow)
    {
        if (shadow) return;

        new Thread(this).start();

    }  // draw


    @Override
    public void run()
    {
        final NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
        final boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();

        if (!isConnected)
        {
            return;
        }


        // get URL
        InputStream inputStream = null;
        HttpsURLConnection connection;
        String UrlString = "";


        // try to get input stream
        try
        {
            for (int index = 0; index < wdStack.getSize(); index++)
            {
                if ((wdStack.getEntry(index).URL != null) &&
                        (wdStack.getEntry(index).onOff))
                {
                    UrlString = wdStack.getEntry(index).URL;     // e.g. "https://en.sat24.com/image?type=km&region=de" for "Germany"

                    URL url = new URL(UrlString);
                    connection = (HttpsURLConnection) url.openConnection();
                    inputStream = connection.getInputStream();   // possible OutOfMemoryError

                    // read the image
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    inputStream.close();
                    inputStream = null;

                    // and put it into ground overlay
                    if ((bitmap != null) && (groundOverlay[index] != null))
                    {
                        groundOverlay[index].setImage(bitmap);
                        wdStack.getEntry(index).downloaded = true;
                    }

                    // show on the map
                    mapView.postInvalidateDelayed(100);
                }  // if onOff
            }  // for index
        }
        catch (Throwable e)
        {
        }

    }  // run

}  // class

任何想法,我可以如何追踪和修复内存泄漏?

【问题讨论】:

  • 我认为你应该在overlay的destroy中取消runnable并释放资源(特别是线程)。
  • 这听起来很合理,但是怎么做呢?你能提供一个代码sn-p吗?我使用 myThread.stop() 和 myThread.destroy() 进行的所有测试都以应用程序崩溃告终。

标签: android out-of-memory overlay android-mapview osmdroid


【解决方案1】:

onDraw(...)是一个重要的方法,必须高效。例如,我们不应该定义任何新变量。因为每当您的视图/叠加层有任何更改时,它都会调用以在屏幕上绘制最新信息。

所以你应该使用承包商来初始化变量,即你的线程。

那么你应该在你的 Overlay 类中覆盖onDetach(MapView)。因为基于 OsmDroid 文档,您应该释放此方法中的所有资源。 (在你的情况下停止并杀死线程和其他巨大的资源)

public void onDetach(MapView mapView)

重写以在关机前执行资源清理。默认 什么都不做。

source

【讨论】:

    【解决方案2】:

    避免内存泄漏的解决方案是活动中的以下代码:

    @Override
    protected void onStop ()
    {
        mapView.onDetach(); 
    
        super.onStop();
    }  // onStop
    

    感谢您的帮助。

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      相关资源
      最近更新 更多