0

基本的に、ユーザーが自分の場所を岩山 (ロック クライミング) として保存できるようにするアプリを作成しています。コンテンツ プロバイダーの背後にあるデータベースに情報を保存しています。しかし、問題は、ユーザーが自分の場所を設定できるようにするために使用している 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 を使用せずに実行している方法や、ASyncTask を使用して実行する方法よりも良い方法はありますか?

4

1 に答える 1

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() に保存することをお勧めします。このようにして、フラグメントがすでに存在し、取得されたタイムスタンプが 5 秒未満であると結論付けた場合、保存された場所を setUpMapIfNeeded() 内で直接設定できます。

場所を一度だけ追加する必要があるため、上記をイタリック体に変更しました。これは完全に不要です。それ以降は、方向が変更されたときにマップが再利用されるため、現在の場所に再度ズームする必要はありません。

注:これにより、最初の修正の前に数秒の遅延が発生することがわかります。私の経験では、他の方法 (LocationManager など) では、GPS がロックされるまで最初の修正が非常に不正確になるため、これより優れた代替手段があるとは思えません。

注2:これはあなたのコードからは明らかではありません。ただし、アクティビティがメインのアクティビティでない場合は、単に LocationClient セットアップをメインのアクティビティに移動し、呼び出されたときに現在の場所を AddCragActivity に渡します。

于 2013-09-24T20:16:04.030 に答える