0

我正在创建一个应用程序,它基本上允许用户将他们的位置保存为峭壁(攀岩)。我将信息保存在内容提供商后面的数据库中。但问题在于设置我用来允许用户设置他们的位置的谷歌地图。目前,我正在使用 onConnected() 方法连接位置提供程序时进行设置,这似乎会减慢活动的启动速度。我试图通过在 ASyncTask 中执行地图内容来加速它,但这会崩溃,因为地图似乎不想在另一个线程中运行。

这是我的代码:

package com.fooforever.climbtrack;

import android.app.Activity;
import android.content.ContentValues;
import android.location.Location;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;

public class AddCragActivity extends Activity implements
    GooglePlayServicesClient.ConnectionCallbacks,
    GooglePlayServicesClient.OnConnectionFailedListener{
    private GoogleMap map;
    private LocationClient locationClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_addcrag);
        locationClient = new LocationClient(this, this, this);
        locationClient.connect();
        setUpMapIfNeeded();
    }

    public void onClickSave(View v) {
        CheckBox tradCb = (CheckBox) findViewById(R.id.tradCb);
        CheckBox boulderCb = (CheckBox) findViewById(R.id.boulderCb);
        CheckBox sportCb = (CheckBox) findViewById(R.id.sportCb);
        EditText cragName = (EditText) findViewById(R.id.cragNameEt);
        String name = cragName.getText().toString();
        String type = "";
        if(tradCb.isChecked()) {
            if(type.isEmpty())
                type = "Trad";
            else
                type = type.concat(" Trad");
        }
        if(boulderCb.isChecked()) {
            if(type.isEmpty())
                type = "Bouldering";
            else
                type = type.concat(" Bouldering");
        }
        if(sportCb.isChecked()) {
            if(type.isEmpty())
                type = "Sport";
            else
                type = type.concat(" Sport");
        }

        Log.d("ClimbTrack", "type = " + type);
        // check for empty strings
        boolean nisE = name.isEmpty();
        boolean tisE = type.isEmpty();

        if(!nisE && !tisE) {
            // put the info into the database
            ContentValues values = new ContentValues();
            values.put(ClimbProvider.NAME, name);
            values.put(ClimbProvider.TYPE, type);
            Uri uri = getContentResolver().insert(ClimbProvider.CONTENT_URI_CRAGS, values);
            Toast.makeText(getBaseContext(), "Saved successfully" , 
                    Toast.LENGTH_SHORT).show();
            // go back an activity
            NavUtils.navigateUpFromSameTask(this);
        } else if(nisE && !tisE)
            Toast.makeText(getBaseContext(), "No crag name!" , 
                    Toast.LENGTH_SHORT).show();
        else if(!nisE && tisE)
            Toast.makeText(getBaseContext(), "No crag type!" , 
                    Toast.LENGTH_SHORT).show();
        else 
            Toast.makeText(getBaseContext(), "No crag name or type!" , 
                    Toast.LENGTH_SHORT).show();

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map.
        if (map == null) {
            map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
                                .getMap();
            // Check if we were successful in obtaining the map.
            if (map != null) {
                // The Map is verified. It is now safe to manipulate the map.

            }
        }
    }

    @Override
    public void onConnectionFailed(ConnectionResult arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onConnected(Bundle arg0) {
        //MapTask mapTask = new MapTask();
        //mapTask.execute();
        map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        map.getUiSettings().setZoomControlsEnabled(false);
        map.getUiSettings().setMyLocationButtonEnabled(true);
        map.setMyLocationEnabled(true);
        Location currentLocation = locationClient.getLastLocation();
        LatLng currentLatLng = new LatLng(currentLocation.getLatitude()
                , currentLocation.getLongitude());
        map.moveCamera(CameraUpdateFactory.newLatLng(currentLatLng));
        map.animateCamera(CameraUpdateFactory.zoomTo(15));

    }

    @Override
    public void onDisconnected() {
        // TODO Auto-generated method stub

    }

//  private class MapTask extends AsyncTask<Void, Void, Void> {
//      @Override
//      protected Void doInBackground(Void... params) {
//          map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
//          map.getUiSettings().setZoomControlsEnabled(false);
//          map.getUiSettings().setMyLocationButtonEnabled(true);
//          map.setMyLocationEnabled(true);
//          Location currentLocation = locationClient.getLastLocation();
//          LatLng currentLatLng = new LatLng(currentLocation.getLatitude()
//                  , currentLocation.getLongitude());
//          map.moveCamera(CameraUpdateFactory.newLatLng(currentLatLng));
//          map.animateCamera(CameraUpdateFactory.zoomTo(15));
//          return null;
//      }}
}

ASyncTask 在这里进行了评论,但这就是我实现它的方式。有没有比我在没有 ASyncTask 或使用 ASyncTask 的情况下做到这一点的方式更好的方法?

4

1 回答 1

0

你是对的,对地图的调用应该发生在 UI 线程中,因此不能在 AsyncTask 中。但是,如果您有一些标记或折线需要从 Internet 获取或以其他方式准备,则最好在后台完成,然后在 onPostExecute 中添加。

我看不出有任何理由在操作地图之前等待 onConnected,而是在 setUpMapIfNeeded() 中执行您需要的所有操作,除了添加当前位置:

   private void setUpMapIfNeeded() {
    // Do a null check to confirm that we have not already instantiated the map.
     if (map == null) {
        map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
                            .getMap();
        // Check if we were successful in obtaining the map.
        if (map != null) {
            // The Map is verified. It is now safe to manipulate the map.
            map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
            map.getUiSettings().setZoomControlsEnabled(false);
            map.getUiSettings().setMyLocationButtonEnabled(true);
            map.setMyLocationEnabled(true);

        }
     }
   }

然后在 onConnected() 中(仅在需要设置时,否则每次方向更改时都会重新缩放):

Location currentLocation = locationClient.getLastLocation();
LatLng currentLatLng = new LatLng(currentLocation.getLatitude()
        , currentLocation.getLongitude());
map.moveCamera(CameraUpdateFactory.newLatLng(currentLatLng));
map.animateCamera(CameraUpdateFactory.zoomTo(15));

如果你真的想处理诸如方向变化之类的事情,那么一个想法是在 onDestroy() 中保存当前时间和当前位置。这样,您可以直接在 setUpMapIfNeeded() 中设置保存的位置,如果您断定片段已经存在并且检索到的时间戳小于 5 秒旧。

将上面的内容更改为斜体,因为这完全没有必要,因为您只需要添加一次位置。从那时起,地图将在方向更改时重复使用,您将不想再次缩放到当前位置。

注意:我可以看到这仍然会在首次修复之前延迟几秒钟。虽然老实说,我怀疑是否有更好的选择,因为根据我的经验,其他方法(例如 LocationManager)在 GPS 锁定之前给出了非常不准确的第一次修复。

注意2:这从您的代码中不清楚。但是,如果活动不是您的主要活动,则只需将 LocationClient 设置移动到您的主要活动,并在调用时将当前位置传递给 AddCragActivity。

于 2013-09-24T20:16:04.030 回答