在 android 屏幕方向更改时重绘 SQL 中的多段线

Redrawing Polylines in SQL on android screen orientation change

我不确定这里的问题是什么,但是这个应用程序会在您通过位置数据移动时跟踪您的路线。我想弄清楚的是为什么当我的屏幕方向发生变化时跟踪线消失并停止跟踪。我的想法是,我可以将我的路线存储到 onSavedInstanceState 中的 SQL 中,并在屏幕方向发生变化时将其恢复到 onRestoreInstanceState 中。由于某种原因它不工作。

变量和 onCreate (MainActivity)

private static final long INTERVAL = 1000;
private static final long FASTEST_INTERVAL = 1000;
private static final long SMALLEST_DISPLACEMENT = 1;
private LocationRequest mLocationRequest;
private Location mCurrentLocation;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
public GoogleMap mMap;
private GoogleApiClient mGoogleApiClient;
public static final String TAG = MapsActivity.class.getSimpleName();
public Polyline line;
public static ArrayList<LatLng> Points;
public DatabaseHelper database = new DatabaseHelper(this);

protected void createLocationRequest(){
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(INTERVAL);
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
    mLocationRequest.setSmallestDisplacement(SMALLEST_DISPLACEMENT);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    createLocationRequest();

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(API)
            .build();
}

在跟踪和画线时存储 LatLng 点。

public Boolean isTracking = false;

public void startNewRoute(View view) {
    Points = new ArrayList<>();
    isTracking = true;
}

@Override
public void onLocationChanged(Location location) {
    mCurrentLocation = location;
    double lat = location.getLatitude();
    double lng = location.getLongitude();
    LatLng latLng = new LatLng(lat, lng);

    if (isTracking){
        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18));
        Points.add(latLng);
        drawLine();
    }
}
public void drawLine(){
    PolylineOptions options = new PolylineOptions()
            .width(5)
            .color(Color.BLUE)
            .geodesic(true);

    for(int a = 0; a < Points.size(); a++){
        LatLng point = Points.get(a);
        double lat = point.latitude;
        double lng = point.longitude;
        Log.d(TAG, "Drawline point got: Lat: "+lat+", Lng: "+lng);
        options.add(point);
        line = mMap.addPolyline(options);
    }
}

在 onSaveInstanceState 中将 ArrayList 中的点保存到数据库中。

    protected void onSaveInstanceState(Bundle savedInstanceState){
    String routeID = "SavedInstance";
    for (int a = 0; a < Points.size(); a++) {
        LatLng point = Points.get(a);
        double lat = point.latitude;
        double lng = point.longitude;
        database.insertSaveInstancePoints(routeID, lat, lng);
        Log.d(TAG, "Point inserted, RID: " + routeID + ", Lat: " + lat + " Lng: " + lng);
    }
    super.onSaveInstanceState(savedInstanceState);
}

这是 SQL 数据库中的 insertSavedInstancePoints()。 (数据库助手)

    public void insertSaveInstancePoints(String routeID, double lat, double lng){
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues cv = new ContentValues();
    cv.put(colSavedID, routeID);
    cv.put(colSavedLat, lat);
    cv.put(colSavedLng, lng);
    db.insert(savedInstanceTable, null, cv);
    db.close();
}

然后最终恢复实例状态。 (主要活动)

 protected void onRestoreInstanceState(Bundle savedInstanceState){
    super.onRestoreInstanceState(savedInstanceState);
    Points = new ArrayList<>();
    database.getSavedPoints();
    drawLine();
}

getSavedPoints()(数据库助手)

 public void getSavedPoints(){
    map = new MapsActivity();
    Log.d(TAG, "getSavedPoints called!");
    String query = "SELECT "+colSavedID+", "+colSavedLat+", "+colSavedLng+" FROM "+savedInstanceTable;
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor c = db.rawQuery(query, null);
    c.moveToFirst();
    for(int a = 0; a < c.getCount(); a++) {
        double lat = c.getDouble(c.getColumnIndex(colSavedLat));
        double lng = c.getDouble(c.getColumnIndex(colSavedLng));
        LatLng latLng = new LatLng(lat, lng);
        map.addToPointsArray(latLng);
        c.moveToNext();
    }
    deleteSavedTableData();
    c.close();
    db.close();
}

将点添加到数组 (MainActivity)

 public void addToPointsArray(LatLng latLng){
    Points.add(latLng);
    Log.d(TAG, "Point Added to Array from DB! " + latLng);
}

现在,当跟踪时屏幕方向发生变化时,它会崩溃,logcat 会这样说:

 12-30 11:29:18.035 29721-29721/com.example.jared.backtrack D/MapsActivity:      Drawline point got: Lat: 47.510955, Lng: -122.1862465
 12-30 11:29:18.045 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.5108991, Lng: -122.186089
 12-30 11:29:18.045 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.5109001, Lng: -122.1861128
 12-30 11:29:18.055 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.5109044, Lng: -122.1861483
 12-30 11:29:20.085 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.510955, Lng: -122.1862465
 12-30 11:29:20.085 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.5108991, Lng: -122.186089
 12-30 11:29:20.085 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.5109001, Lng: -122.1861128
 12-30 11:29:20.085 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.5109044, Lng: -122.1861483
 12-30 11:29:20.095 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.5109081, Lng: -122.1861328
 12-30 11:29:22.225 29721-29721/com.example.jared.backtrack D/MapsActivity: Point inserted, RID: SavedInstance, Lat: 47.510955 Lng: -122.1862465
 12-30 11:29:22.235 29721-29721/com.example.jared.backtrack D/MapsActivity: Point inserted, RID: SavedInstance, Lat: 47.5108991 Lng: -122.186089
 12-30 11:29:22.265 29721-29721/com.example.jared.backtrack D/MapsActivity: Point inserted, RID: SavedInstance, Lat: 47.5109001 Lng: -122.1861128
 12-30 11:29:22.295 29721-29721/com.example.jared.backtrack D/MapsActivity: Point inserted, RID: SavedInstance, Lat: 47.5109044 Lng: -122.1861483
 12-30 11:29:22.305 29721-29721/com.example.jared.backtrack D/MapsActivity: Point inserted, RID: SavedInstance, Lat: 47.5109081 Lng: -122.1861328
 12-30 11:29:22.405 29721-29721/com.example.jared.backtrack I/Google Maps Android API: Google Play services package version: 8489038
 12-30 11:29:22.455 29721-29721/com.example.jared.backtrack D/DatabaseHelper: getSavedPoints called!
 12-30 11:29:22.465 29721-29721/com.example.jared.backtrack D/MapsActivity: Point Added to Array from DB! lat/lng: (47.510955,-122.1862465)
 12-30 11:29:22.465 29721-29721/com.example.jared.backtrack D/MapsActivity: Point Added to Array from DB! lat/lng: (47.5108991,-122.186089)
 12-30 11:29:22.475 29721-29721/com.example.jared.backtrack D/MapsActivity: Point Added to Array from DB! lat/lng: (47.5109001,-122.1861128)
 12-30 11:29:22.475 29721-29721/com.example.jared.backtrack D/MapsActivity: Point Added to Array from DB! lat/lng: (47.5109044,-122.1861483)
 12-30 11:29:22.475 29721-29721/com.example.jared.backtrack D/MapsActivity: Point Added to Array from DB! lat/lng: (47.5109081,-122.1861328)
 12-30 11:29:22.505 29721-29721/com.example.jared.backtrack D/MapsActivity: Drawline point got: Lat: 47.510955, Lng: -122.1862465
 12-30 11:29:22.505 29721-29721/com.example.jared.backtrack D/AndroidRuntime: Shutting down VM
 12-30 11:29:22.505 29721-29721/com.example.jared.backtrack W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41e92d88)
 12-30 11:29:22.515 29721-29721/com.example.jared.backtrack E/AndroidRuntime: FATAL EXCEPTION: main

所以你可以从我的调试日志中看到它正在跟踪路线,正在绘制线条,当屏幕旋转时,点已成功加载到 SQl 然后检索。一旦启动 drawline 方法,它就会尝试绘制第一个点,崩溃并显示空指针异常。

有什么想法吗?

您正在 #getSavedPoints 中实例化一个新的 MapsActivity(我假设这就是您在问题中调用的 MainActivity?)并在该实例上设置数据。该实例不是系统在旋转时重新创建后显示在屏幕上的实例。

相反,将#getSavedPoints return 设为点的 ArrayList,并将其设置为 activity 中的点字段。

public List<LatLng> getSavedPoints(){
  List<LatLng> points = new ArrayList();
  Log.d(TAG, "getSavedPoints called!");
  String query = "SELECT "+colSavedID+", "+colSavedLat+", "+colSavedLng+" FROM "+savedInstanceTable;
  SQLiteDatabase db = this.getReadableDatabase();
  Cursor c = db.rawQuery(query, null);
  c.moveToFirst();
  for(int a = 0; a < c.getCount(); a++) {
    double lat = c.getDouble(c.getColumnIndex(colSavedLat));
    double lng = c.getDouble(c.getColumnIndex(colSavedLng));
    LatLng latLng = new LatLng(lat, lng);
    points.add(latLng);
    c.moveToNext();
  }
  deleteSavedTableData();
  c.close();
  db.close();
  return points;
}

在onRestoreInstanceState

protected void onRestoreInstanceState(Bundle savedInstanceState){
  super.onRestoreInstanceState(savedInstanceState);
  Points = database.getSavedPoints();
  drawLine();
}

此外,您无需使用数据库即可执行此操作。如果你的 LatLng class 只是两个双打的 class,让它实现 Parcelable 然后你就可以 put/retrieve onSaveInstanceState/onRestoreInstanceState 中的包中的 Points 对象。实现 Parcelable 有一些设置,但应该很容易理解。

以上只是一个建议,如果您没有注意到使用数据库的性能瓶颈,那么就坚持使用有效的方法。

感谢@BG_NE,我们发现问题是我的 mMap GoogleMap 对象在 onRestoreInstanceState() 期间没有被初始化,所以 drawLine() 方法指向 null,因为没有地图。

所以解决方案是将 drawLine() 从 onRestoreInstanceState() 移动到 onMapReady() 并传递一个布尔值来检查是否正在恢复某些内容。

代码如下:

protected void onRestoreInstanceState(Bundle savedInstanceState){
    super.onRestoreInstanceState(savedInstanceState);

/////Set restorePoints to true.
    restorePoints = true;           
    Points = database.getSavedPoints();
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    mMap.setMyLocationEnabled(true);
    mMap.getUiSettings().setZoomControlsEnabled(true);
    mMap.getUiSettings().setAllGesturesEnabled(true);

///// Here I draw the line during onMapReady();
    if(restorePoints){
        drawLine();
        restorePoints = false;
    }
}