質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.58%

googlemap で現在地の位置情報を取得したいが NullPointerException となる件

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,803

[MapsActivity.java]

public class MapsActivity extends FragmentActivity 
    implements OnMapReadyCallback, LocationListener, 
                CompoundButton.OnCheckedChangeListener {
    private GoogleMap mMap;
    private LatLng latlong;
    private static Location location1;
    LocationManager locationmanager1;


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

        locationmanager1 = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        String provider = locationmanager1.getBestProvider(criteria, true);
        if (ActivityCompat.checkSelfPermission(this,
           Manifest.permission.ACCESS_FINE_LOCATION) !=
           PackageManager.PERMISSION_GRANTED &&
           ActivityCompat.checkSelfPermission(this,
               Manifest.permission.ACCESS_COARSE_LOCATION) !=
               PackageManager.PERMISSION_GRANTED) {
            // ↓「アクセスを許可しますか?」
            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_CODE);
            return;
        } else {
            locationmanager1.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
        }
        location1 = locationmanager1.getLastKnownLocation(provider);
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        lat = location1.getLatitude();  // ★186行目
        lon = location1.getLongitude();
        latlong = new LatLng(lat, lon);
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlong, 19));
        locationmanager1.removeUpdates(this);
    }


    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        switch (status) {
            case LocationProvider.AVAILABLE:
                Log.d("debug", "LocationProvider.AVAILABLE");
                break;
            case LocationProvider.OUT_OF_SERVICE:
                Log.d("debug", "LocationProvider.OUT_OF_SERVICE");
                break;
            case LocationProvider.TEMPORARILY_UNAVAILABLE:
                Log.d("debug", "LocationProvider.TEMPORARILY_UNAVAILABLE");
                break;
        }
    }
    @Override
    public void onLocationChanged(Location location) {
        LatLng curr = new LatLng(location.getLatitude(), location.getLongitude());
        mMap.animateCamera(CameraUpdateFactory.newLatLng(curr));
    }
    @Override
    public void onProviderEnabled(String s) {
    }
    @Override
    public void onProviderDisabled(String s) {
    }
}


アプリ起動時だけ現在位置座標を取得し、ぞの座標位置を画面の中央に表示させる、ということをしたいです。


.getLatitude()、.getLongitude() で緯度経度の数値を取得したいのですが、上記のコードを実行すると

2-15 01:16:49.256 11700-11700/jp.path.appname E/AndroidRuntime: FATAL EXCEPTION: main
    Process: jp.path.appname, PID: 11700
    java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
        at jp.path.appname.MapsActivity.onMapReady(MapsActivity.java:186)


とのエラーから、onMapReady において location1 が空だという内容です。
.getLastKnownLocation の代入が効いていないようにも読めます。

お知恵をお借りできますと幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

        if (ActivityCompat.checkSelfPermission(this,
           Manifest.permission.ACCESS_FINE_LOCATION) !=
           PackageManager.PERMISSION_GRANTED &&
           ActivityCompat.checkSelfPermission(this,
               Manifest.permission.ACCESS_COARSE_LOCATION) !=
               PackageManager.PERMISSION_GRANTED) {
            // ↓「アクセスを許可しますか?」
            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_CODE);
            return;
        } else {
            locationmanager1.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
        }
        location1 = locationmanager1.getLastKnownLocation(provider);

この構造だと、初回の起動でrequestPermissions()側に進むと、許可を得たら即座にreturnによって抜けてしまい、location1が設定されることなく進行してしまうので、NullPointerExceptionになるのは必然と思われます。returnを除去することで解決できませんか?

なお、許可しない選択をしたときもやはり同様に落ちると思われますので、その処理は別途必要になるでしょう。


(15:13追記)
許可を得られる前にonMapReady()が走ってしまったりとか、いろいろ前後関係がありそうですね。処理を組み直さないと解決できなさそうなので、ざっと書いてみましたが、こんな感じで解決できるでしょうか?

public class MapsActivity extends FragmentActivity
        implements OnMapReadyCallback, LocationListener,
        CompoundButton.OnCheckedChangeListener {
    private GoogleMap mMap;
    private LatLng latlong;
    private static Location location1;
    LocationManager locationmanager1;
    private static final int LOCATION_CODE = 100;
    private static final String[] LOCATION_PERMISSION = {
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
    };
    private static final int GRANTED = PackageManager.PERMISSION_GRANTED;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ここではまだsetContentView()は呼ばない

        locationmanager1 = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        if (ActivityCompat.checkSelfPermission(this, LOCATION_PERMISSION[0]) != GRANTED &&
                ActivityCompat.checkSelfPermission(this, LOCATION_PERMISSION[1]) != GRANTED) {
            // ↓「アクセスを許可しますか?」
            requestPermissions(LOCATION_PERMISSION, LOCATION_CODE);
        } else {
            startLocation();
        }
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {

        mMap = googleMap;
        double lat = location1.getLatitude();
        double lon = location1.getLongitude();
        latlong = new LatLng(lat, lon);
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlong, 19));
        locationmanager1.removeUpdates(this);
    }

    // アクセス許可のダイアログで操作を行ったときに呼ばれるメソッド
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == LOCATION_CODE) {
            if (grantResults[0] == GRANTED) {
                startLocation();
            } else {
                // 拒否されたのならアプリ続行不可能
                finish();
            }
        }

    }

    void startLocation() {
        if (ActivityCompat.checkSelfPermission(this, LOCATION_PERMISSION[0]) == GRANTED ||
                ActivityCompat.checkSelfPermission(this, LOCATION_PERMISSION[1]) == GRANTED) {

            // 許可を得られたことを確認できた段階で初めてsetContentView()を呼ぶ
            // onMapReady()が走るのはこれ以後になる
            setContentView(R.layout.activity_maps);
            SupportMapFragment mapFragment =
                    (SupportMapFragment) getSupportFragmentManager()
                            .findFragmentById(R.id.map_goo_fra);
            mapFragment.getMapAsync(this);

            Criteria criteria = new Criteria();
            criteria.setAccuracy(Criteria.ACCURACY_FINE);
            String provider = locationmanager1.getBestProvider(criteria, true);
            locationmanager1.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
            location1 = locationmanager1.getLastKnownLocation(provider);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        locationmanager1.removeUpdates(this);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        switch (status) {
            case LocationProvider.AVAILABLE:
                Log.d("debug", "LocationProvider.AVAILABLE");
                break;
            case LocationProvider.OUT_OF_SERVICE:
                Log.d("debug", "LocationProvider.OUT_OF_SERVICE");
                break;
            case LocationProvider.TEMPORARILY_UNAVAILABLE:
                Log.d("debug", "LocationProvider.TEMPORARILY_UNAVAILABLE");
                break;
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        //LatLng curr = new LatLng(location.getLatitude(), location.getLongitude());
        //mMap.animateCamera(CameraUpdateFactory.newLatLng(curr));
    }

    @Override
    public void onProviderEnabled(String s) {
    }

    @Override
    public void onProviderDisabled(String s) {
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/15 13:07

    ご回答ありがとうございます。
    return; 除去→同じエラー という状況です。
    書籍で緯度経度を取得するだけのサンプルを比較のために試しています。・・・

    キャンセル

  • 2018/12/15 16:57 編集

    【解消】現在地座標取得および画面上での中心表示、できました。
    setContentView の切り離し、とても思いつきません。
    いや、すばらしいです。ただただ感謝です。

    【経緯】
    1. Android認定試験参考書のサンプルコードや受講している講義で使用した書籍のそれをそのまま試しても全て同エラーにて失敗しました。
    2. 比較のために試みた、緯度経度の取得→テキストで通知表示については、私が調べた中では唯一 https://techblog.recochoku.jp/705 さんのコードが動いてくれました。
    しかしそれを上記作成中コードにあてはめても、挿入箇所をいろいろ試しましたが、全て失敗でした。

    onCreate, onMapReady, onStatusChanged, onLocationChanged、そしてstartLocation, onDestroy が重要ですね。制御の順番を見抜く目がないといけませんね。勉強になりました。

    --- --- ---

    【追記】
    日が変わっておもむろに起動したところ、同エラーが再発し、アプリがすぐに落ちました。
    試行錯誤の結果、.getLastKnownLocation(provider) のほかに、.getLastKnownLocation(LocationManager.GPS_PROVIDER) および .getLastKnownLocation(LocationManager.NETWORK_PROVIDER) も加えて3重にチェック網を築いたところ、さらに日が変わって様子を見てますが、現在地を捕捉するようです。

    void startLocation() {
    if (ActivityCompat.checkSelfPermission(this, LOCATION_PERMISSION[0]) == GRANTED ||
    ActivityCompat.checkSelfPermission(this, LOCATION_PERMISSION[1]) == GRANTED) {

    // 許可を得られたことを確認できた段階で初めてsetContentView()を呼ぶ
    // onMapReady()が走るのはこれ以後になる
    setContentView(R.layout.activity_maps);
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map_goo_fra);
    mapFragment.getMapAsync(this);

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_FINE);
    String provider = locationmanager1.getBestProvider(criteria, true);
    // ↓第2引数は0以上が好ましいようです
    locationmanager1.requestLocationUpdates(provider, 10000, 0, this);
    location1 = locationmanager1.getLastKnownLocation(provider);
    if (location1 == null) {
    location1 = locationmanager1.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    }
    if (location1 == null) {
    location1 = locationmanager1.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
    }
    }
    }


    最初の質問のコードに3重チェック網を追記しても、同エラーでした。そのことからでも、setContentView の切り離し以下のロジックの有効性が明らかになりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る