我正在创建一个基本上允许用户将其位置保存为岩壁(攀岩)的应用程序。我将信息保存在内容提供商后面的数据库中。但问题在于设置我用来允许用户设置其位置的Google地图。目前我正在设置连接位置提供程序时使用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或者用一种方法来做它?
答案 0 :(得分:0)
你是对的,调用地图应该在UI线程中发生,因此不能在AsyncTask中。但是如果你有一些标记或折线你需要从互联网上获取或以其他方式准备,最好在后台完成,然后在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。