【问题标题】:Google Maps: How to restore markers when resuming map activity谷歌地图:恢复地图活动时如何恢复标记
【发布时间】:2017-09-14 15:53:26
【问题描述】:

我正在制作一个从传感器收集数据的应用。每次传感器发送数据时,都会在地图上放置一个新标记。当我按回然后恢复地图活动时,所有标记都消失了。有没有办法在恢复活动时使用其唯一的 MarkerOptions (title,sn-p,LatLng) 保存和恢复每个唯一标记?

这是我的地图活动

 public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener
{

private GoogleMap mMap;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
private int co_mV;
private int no2_mV;
LocationRequest mLocationRequest;
private boolean initiateApp;
String currentTime;

TcpClient mTcpClient;
ArrayList<Marker> markerArrayList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);

    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        checkLocationPermission();
    }
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    initiateApp = true;
    markerArrayList = new ArrayList<Marker>();

}

/**
 * Manipulates the map once available.
 * This callback is triggered when the map is ready to be used.
 * This is where we can add markers or lines, add listeners or move the camera. In this case,
 * we just add a marker near Sydney, Australia.
 * If Google Play services is not installed on the device, the user will be prompted to install
 * it inside the SupportMapFragment. This method will only be triggered once the user has
 * installed Google Play services and returned to the app.
 */
@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
    mMap.setMyLocationEnabled(true);


    if(mGoogleApiClient == null) {
    //Initialize Google Play Services
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            buildGoogleApiClient();

        }
    }
    else {
            buildGoogleApiClient();
        }
    }
}

/* Here we create the infoWindow **/
protected synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    mGoogleApiClient.connect();

}

@Override
public void onConnected(Bundle bundle) {

    getNewLocation();
    new ConnectTask().execute("");

}


public void newData(JSONObject d) {
    try {
        co_mV = d.getInt("co_mV");
        no2_mV = d.getInt("no2_mV");
    } catch (JSONException e) {
        e.printStackTrace();
    }

    getNewLocation();
}

public void getTime() {

    Calendar cal = Calendar.getInstance();
    currentTime = new SimpleDateFormat("HH:mm:ss").format(cal.getTime());

}

public void getNewLocation() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onLocationChanged(Location location) {

    if (markerArrayList.size()>1) {
        if(location.distanceTo(mLastLocation) < 30) {
            markerArrayList.get(markerArrayList.size()-1).remove();
            markerArrayList.remove(markerArrayList.size()-1);
            Toast.makeText(
                    getApplicationContext(),
                    "Reading to close to last reading, replaces last reading", Toast.LENGTH_SHORT).show();
        }
    }


    if (markerArrayList.size() == 8) {
        markerArrayList.get(0).remove();
        markerArrayList.remove(0);
    }

    //Place current location marker
    LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());

    if (!initiateApp) {
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Time of reading: " + currentTime);
        markerOptions.snippet("co: " + String.valueOf(co_mV) + " mV, " + "no2: " + String.valueOf(no2_mV) + " mV");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        mCurrLocationMarker = mMap.addMarker(markerOptions);
        markerArrayList.add(mCurrLocationMarker);

    }

    mLastLocation = location;


    Log.d("ADebugTag", "Value: " + Double.toString(location.getLatitude()));
    Log.d("ADebugTag", "Value: " + Double.toString(location.getLongitude()));


    //move map camera

    if(initiateApp){
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
    }

    boolean contains = mMap.getProjection()
            .getVisibleRegion()
            .latLngBounds
            .contains(latLng);

    if(!contains){
        mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
    }

    initiateApp = false;
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

}

public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission(){
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {

        // Asking user if explanation is needed
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {

            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.

            //Prompt the user once explanation has been shown
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_LOCATION);


        } else {
            // No explanation needed, we can request the permission.
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_LOCATION);
        }
        return false;
    } else {
        return true;
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_LOCATION: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted. Do the
                // contacts-related task you need to do.
                if (ContextCompat.checkSelfPermission(this,
                        Manifest.permission.ACCESS_FINE_LOCATION)
                        == PackageManager.PERMISSION_GRANTED) {

                    if (mGoogleApiClient == null) {
                        buildGoogleApiClient();
                    }
                    mMap.setMyLocationEnabled(true);
                }

            } else {

                // Permission denied, Disable the functionality that depends on this permission.
                Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
            }
            return;
        }

        // other 'case' lines to check for other permissions this app might request.
        // You can add here other case statements according to your requirement.
    }
}

ublic JSONObject getNewJSON(JSONObject json) {
    try {

        int humidity = json.getInt("humidity_ppm");
        int pressure = json.getInt("pressure_Pa");
        int noise = json.getInt("noise_dB");
        double lat = mLastLocation.getLatitude();
        double lng = mLastLocation.getLongitude();
        long time = System.currentTimeMillis() / 1000L;

       JSONObject c = new JSONObject();
        c.put("time",time);
        c.put("lat",lat);
        c.put("long",lng);
        c.put("humidity",humidity);
        c.put("pressure",pressure);
        c.put("noise_dB",noise);
        return c;

    } catch (JSONException e) {
        e.printStackTrace();
    }

return null;
}


public class ConnectTask extends AsyncTask<String, String, TcpClient> {

    @Override
    protected TcpClient doInBackground(String... message) {

        //we create a TCPClient object
        mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
            @Override
            //here the messageReceived method is implemented
            public void messageReceived(String message) {
                //this method calls the onProgressUpdate
                publishProgress(message);
            }
        });
        mTcpClient.run();

        return null;
    }

    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);


        try {
            JSONObject parser = new JSONObject(values[0]);
            JSONObject d = parser.getJSONObject("d");
            JSONObject cloudData = getNewJSON(d);

            if (mLastLocation != null) {
                newData(d);
                getTime();
            }

            System.out.println(cloudData);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        //process server response here....
    }

}

【问题讨论】:

    标签: java android google-maps google-maps-markers google-maps-android-api-2


    【解决方案1】:

    你说

    当我按回然后恢复地图时

    对吗?没有关闭您的应用。

    最简单的方法是重写onBackPressed方法,像这样:

    @Override
    public void onBackPressed() {
        moveTaskToBack(true);
    }
    

    这不会再次触发onDestroy()onCreate(),因此您的Activity 实例不会被修改。够简单吧?

    【讨论】:

    • 谢谢。可悲的是,当您旋转手机时,地图会被强行破坏和重建,所以我想我也必须使用其他答案
    【解决方案2】:

    您可以创建一个使用来自服务器的新数据填充的函数。然后,您可以在服务器发送 JSON 数据后立即调用该函数。要回答您的问题,您只需在 onResume 中调用相同的函数。有关活动状态的更多信息,请阅读this

    另一种方法是将其保存在 savedInstanceState 包中,并像 this SO accepted answer 一样检查 onSaveInstanceState,如果该包不为空,则使用列表填充地图(标记的最后已知位置,如果可行的话与您的项目)。否则只需加载地图。

    【讨论】:

    • 我不太明白你的意思?我已经有一个名为 newData() 的方法,当服务器发送 JSON 数据时会调用它?我为此编辑了代码。你的意思是我需要做什么?
    • 你需要重写Activity类的onPause和onResume方法。然后,您创建一个类范围的 List 或其他东西以将标记保存在 onPause() 方法中,然后在 onResume() 方法中引用该 List,在您的情况下为 newData() 。当活动停止和恢复时,系统分别调用这两种方法。
    • 感谢您的回答。我有一个“markerArray”ArrayList,它在“OnLocationChanged”上填充了我的标记。我怎样才能使这个 ArrayList 保存在 onPause() 中?
    • 将其设为静态是否有效?所以当我按下后退按钮时它不会变为空?
    • 对不起,我下班了,但我现在已经更新了我的答案。让我知道这是否适合您。
    【解决方案3】:

    我找到了this answer,它提供了一种优雅的单线解决方案。这将在用户旋转手机时恢复标记,但不会在他按下 Back 按钮时恢复(我知道这不是 OP 所要求的,但 Google 会带领人们来到这里)

    onCreate中添加以下内容:

    // mapFragment is a SupportMapFragment 
    mapFragment.setRetainInstance(true);
    

    【讨论】:

      【解决方案4】:

      在清单文件中,您可以添加以下行:

          <activity android:name=".MapsActivity"
                    android:configChanges="orientation|screenSize">
      

      这是对我来说最简单的解决方案之一

      @Override
      public void onBackPressed() {
      moveTaskToBack(true);
      }
      

      ,并且适用于足够简单的应用程序,但也推荐使用 onSaveInstanceState() 方法。我从研究中发现很难序列化和反序列化标记列表,并且 onSaveInstanceState() 仅适用于字符串等简单对象。如果有人找到更好的解决方案,也请告诉我:)

      【讨论】:

        猜你喜欢
        • 2017-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-08
        • 2017-10-18
        • 1970-01-01
        相关资源
        最近更新 更多