Google Play Serviceを利用する新位置情報取得APIについて 実装方法

Android
Google Play Serviceを利用する新位置情報取得APIについて まとめ

注意:2016年6月、AndroidStudio]]ではGoogle Play Serviceを読み込めませんので、この方法は利用できません。[[Android Cannot resolve symbol GooglePlayServicesClientを参照してください。

Google Play Serviceを利用する新位置情報取得APIについて 実装方法

サンプル

Googleさんがサンプルを配ってくれています。
大変ありがたいことですね!
下記からダウンロードできます。

下記のURLの、Dowonload the sampleという青いボタンをクリックして、LocationUpdates.zipをダウンロードします。
http://developer.android.com/training/location/retrieve-current.html

この
package com.example.android.locationのMainActivityを例にとって、ちょこちょこ解説していきます。

と、その前に!
Google play Service Libraryは読み込みましたか?

エラーばかりになってしまう…
という場合は、Google play Service Libraryがプロジェクトに読み込まれていない可能性が高いですね。

Google play Service Libraryの読み込み方をプロジェクトに読み込む方法がわからない場合は、下記の記事の前半までに書いてありますので、読んでみてください。
Google Map Android Api Ver2之サンプルを動かしてみよう!

いよいよ実装…

上記に紹介したサンプルを使って、新APIについて、紹介していきます。
これはボタンを押すと、スケジュールで位置情報を取得するアプリです。

package com.example.android.location;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;

import android.content.IntentSender;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

public class MainActivity extends FragmentActivity implements
LocationListener,
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {

// A request to connect to Location Services
private LocationRequest mLocationRequest;

// Stores the current instantiation of the location client in this object
private LocationClient mLocationClient;

// Handles to UI widgets
private TextView mLatLng;
private TextView mAddress;
private ProgressBar mActivityIndicator;
private TextView mConnectionState;
private TextView mConnectionStatus;

// Handle to SharedPreferences for this app
SharedPreferences mPrefs;

// Handle to a SharedPreferences editor
SharedPreferences.Editor mEditor;

/*
* Note if updates have been turned on. Starts out as “false”; is set to “true” in the
* method handleRequestSuccess of LocationUpdateReceiver.
*
*/
boolean mUpdatesRequested = false;

/*
* Initialize the Activity
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Get handles to the UI view objects
mLatLng = (TextView) findViewById(R.id.lat_lng);
mAddress = (TextView) findViewById(R.id.address);
mActivityIndicator = (ProgressBar) findViewById(R.id.address_progress);
mConnectionState = (TextView) findViewById(R.id.text_connection_state);
mConnectionStatus = (TextView) findViewById(R.id.text_connection_status);

// Create a new global location parameters object
mLocationRequest = LocationRequest.create();

/*
* Set the update interval
*/
mLocationRequest.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);

// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

// Set the interval ceiling to one minute
mLocationRequest.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

// Note that location updates are off until the user turns them on
mUpdatesRequested = false;

// Open Shared Preferences
mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES, Context.MODE_PRIVATE);

// Get an editor
mEditor = mPrefs.edit();

/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
mLocationClient = new LocationClient(this, this, this);

}

/*
* Called when the Activity is no longer visible at all.
* Stop updates and disconnect.
*/
@Override
public void onStop() {

// If the client is connected
if (mLocationClient.isConnected()) {
stopPeriodicUpdates();
}

// After disconnect() is called, the client is considered “dead”.
mLocationClient.disconnect();

super.onStop();
}

@Override
public void onPause() {

// Save the current setting for updates
mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, mUpdatesRequested);
mEditor.commit();

super.onPause();
}

@Override
public void onStart() {

super.onStart();

mLocationClient.connect();

}

@Override
public void onResume() {
super.onResume();

// If the app already has a setting for getting location updates, get it
if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) {
mUpdatesRequested = mPrefs.getBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);

// Otherwise, turn off location updates until requested
} else {
mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
mEditor.commit();
}

}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

// Choose what to do based on the request code
switch (requestCode) {

// If the request code matches the code sent in onConnectionFailed
case LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST :

switch (resultCode) {
// If Google Play services resolved the problem
case Activity.RESULT_OK:

// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.resolved));

// Display the result
mConnectionState.setText(R.string.connected);
mConnectionStatus.setText(R.string.resolved);
break;

// If any other result was returned by Google Play services
default:
// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.no_resolution));

// Display the result
mConnectionState.setText(R.string.disconnected);
mConnectionStatus.setText(R.string.no_resolution);

break;
}

// If any other request code was received
default:
// Report that this Activity received an unknown requestCode
Log.d(LocationUtils.APPTAG,
getString(R.string.unknown_activity_request_code, requestCode));

break;
}
}

private boolean servicesConnected() {

// Check that Google Play services is available
int resultCode =
GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
Log.d(LocationUtils.APPTAG, getString(R.string.play_services_available));

// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0);
if (dialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(dialog);
errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG);
}
return false;
}
}

public void getLocation(View v) {

// If Google Play Services is available
if (servicesConnected()) {

// Get the current location
Location currentLocation = mLocationClient.getLastLocation();

// Display the current location in the UI
mLatLng.setText(LocationUtils.getLatLng(this, currentLocation));
}
}

@SuppressLint(“NewApi”)
public void getAddress(View v) {

// In Gingerbread and later, use Geocoder.isPresent() to see if a geocoder is available.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && !Geocoder.isPresent()) {
// No geocoder is present. Issue an error message
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}

if (servicesConnected()) {

// Get the current location
Location currentLocation = mLocationClient.getLastLocation();

// Turn the indefinite activity indicator on
mActivityIndicator.setVisibility(View.VISIBLE);

// Start the background task
(new MainActivity.GetAddressTask(this)).execute(currentLocation);
}
}

public void startUpdates(View v) {
mUpdatesRequested = true;

if (servicesConnected()) {
startPeriodicUpdates();
}
}

public void stopUpdates(View v) {
mUpdatesRequested = false;

if (servicesConnected()) {
stopPeriodicUpdates();
}
}

@Override
public void onConnected(Bundle bundle) {
mConnectionStatus.setText(R.string.connected);

if (mUpdatesRequested) {
startPeriodicUpdates();
}
}

@Override
public void onDisconnected() {
mConnectionStatus.setText(R.string.disconnected);
}

/*
* Called by Location Services if the attempt to
* Location Services fails.
*/
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
try {

// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(
this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);

/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/

} catch (IntentSender.SendIntentException e) {

// Log the error
e.printStackTrace();
}
} else {

// If no resolution is available, display a dialog to the user with the error.
showErrorDialog(connectionResult.getErrorCode());
}
}

@Override
public void onLocationChanged(Location location) {

// Report to the UI that the location was updated
mConnectionStatus.setText(R.string.location_updated);

// In the UI, set the latitude and longitude to the value received
mLatLng.setText(LocationUtils.getLatLng(this, location));
}

private void startPeriodicUpdates() {

mLocationClient.requestLocationUpdates(mLocationRequest, this);
mConnectionState.setText(R.string.location_requested);
}

private void stopPeriodicUpdates() {
mLocationClient.removeLocationUpdates(this);
mConnectionState.setText(R.string.location_updates_stopped);
}

protected class GetAddressTask extends AsyncTask {

// Store the context passed to the AsyncTask when the system instantiates it.
Context localContext;

// Constructor called by the system to instantiate the task
public GetAddressTask(Context context) {

// Required by the semantics of AsyncTask
super();

// Set a Context for the background task
localContext = context;
}

@Override
protected String doInBackground(Location… params) {
Geocoder geocoder = new Geocoder(localContext, Locale.getDefault());

// Get the current location from the input parameter list
Location location = params[0];

// Create a list to contain the result address
List

addresses = null;

// Try to get an address for the current location. Catch IO or network problems.
try {

addresses = geocoder.getFromLocation(location.getLatitude(),
location.getLongitude(), 1
);

// Catch network or other I/O problems.
} catch (IOException exception1) {

// Log an error and return an error message
Log.e(LocationUtils.APPTAG, getString(R.string.IO_Exception_getFromLocation));

// print the stack trace
exception1.printStackTrace();

// Return an error message
return (getString(R.string.IO_Exception_getFromLocation));

// Catch incorrect latitude or longitude values
} catch (IllegalArgumentException exception2) {

// Construct a message containing the invalid arguments
String errorString = getString(
R.string.illegal_argument_exception,
location.getLatitude(),
location.getLongitude()
);
// Log the error and print the stack trace
Log.e(LocationUtils.APPTAG, errorString);
exception2.printStackTrace();

//
return errorString;
}
// If the reverse geocode returned an address
if (addresses != null && addresses.size() > 0) {

// Get the first address
Address address = addresses.get(0);

// Format the first line of address
String addressText = getString(R.string.address_output_string,

// If there’s a street address, add it
address.getMaxAddressLineIndex() > 0 ?
address.getAddressLine(0) : “”,

// Locality is usually a city
address.getLocality(),

// The country of the address
address.getCountryName()
);

// Return the text
return addressText;

// If there aren’t any addresses, post a message
} else {
return getString(R.string.no_address_found);
}
}

/**
* A method that’s called once doInBackground() completes. Set the text of the
* UI element that displays the address. This method runs on the UI thread.
*/
@Override
protected void onPostExecute(String address) {

// Turn off the progress bar
mActivityIndicator.setVisibility(View.GONE);

// Set the address in the UI
mAddress.setText(address);
}
}

private void showErrorDialog(int errorCode) {

// Get the error dialog from Google Play services
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
errorCode,
this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);

// If Google Play services can provide an error dialog
if (errorDialog != null) {

// Create a new DialogFragment in which to show the error dialog
ErrorDialogFragment errorFragment = new ErrorDialogFragment();

// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);

// Show the error dialog in the DialogFragment
errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG);
}
}

/**
* Define a DialogFragment to display the error dialog generated in
* showErrorDialog.
*/
public static class ErrorDialogFragment extends DialogFragment {

// Global field to contain the error dialog
private Dialog mDialog;

/**
* Default constructor. Sets the dialog field to null
*/
public ErrorDialogFragment() {
super();
mDialog = null;
}

/**
* Set the dialog to display
*
* @param dialog An error dialog
*/
public void setDialog(Dialog dialog) {
mDialog = dialog;
}

/*
* This method must return a Dialog to the DialogFragment.
*/
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
}

まずは

 LocationListener,
 GooglePlayServicesClient.ConnectionCallbacks,
 GooglePlayServicesClient.OnConnectionFailedListener

を実装します。

OnCreatedの

 mLocationRequest = LocationRequest.create();

が、位置情報のリクエストを定期的に行うリクエストを作っています。

 mLocationClient = new LocationClient(this, this, this);

でLocationClientを作っています。

肝心なポイント①は、

 private boolean servicesConnected() {
        int resultCode =
                GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

ですね。
このアプリでは、アプリを動作させるスマホに、Google Play 開発者サービスがインストールされ、最新バージョンである必要があります。
それを判断して、Google Play 開発者サービスが最新でなかったり、インストールされていなければ、ユーザーにインストールなどを促すダイアログを表示します。

肝心なポイント②は

 public void onConnected(Bundle bundle) 

 public void onDisconnected() 

です。

Google Play ServiceにコネクトしたらOnConnectedが呼ばれます。
Google Play Serviceからの接続が切れると、onDisconnectedが呼ばれます。

現在地を取得するのは

 Location currentLocation = mLocationClient.getLastLocation();

でできますが、これもOnConnectedが呼ばれた後で呼び出さないといけません。

そういえば、AndroidOS2.2では、

 Location getLastKnownLocation

とやって、「一番最近に取得された位置情報」しか返してくれなかったのですが、「今いる場所」をこれで取得してくれるようになったわけです。
嬉しいですね![smile]

 public void onConnectionFailed(ConnectionResult connectionResult) 

はGoogle play Serviceへの接続が何かしらの要因で失敗してしまった場合

 startActivityForResult()

が呼ばれ、結果として
が呼ばれます。

 protected void onActivityResult(int requestCode, int resultCode, Intent intent) 

他の部分は、以前のLocationListenerとそんなに変わりません。

Google Play Serviceを利用する新位置情報取得APIについて まとめ

Android

Google Play Serviceを利用する新位置情報取得APIについて まとめ

AndroidのGoogle Play Serviceを利用する位置情報APIについて、そこそこ実装できてきましたので、少しまとめておきたいと思います。

AndroidのGoogle Play Serviceを利用する位置情報APIは、特に名前もないのですが、以前のLocationManagerを使う位置情報取得の流れとは、さまざまな点で変わりました。
fused location providerと呼んでいる人もいますが、これはプロバイダの名前が、fused location providerというものになったというわけで、一部の機能だけのことです。

位置情報の精度

これは弊社で試してみたところの実感なので、厳密に計測したわけではありません。
位置情報の精度は、GPSで計測できるものはそれほど変わりませんね。
多少よくなったか、という感じですが、相変わらず、機種による差が大きいようです。

大きく改善されたのは、Wi-fiによる位置情報です。
ぶれている時は、相変わらず大きくぶれていますが、Wi-Fiの位置情報だけで、ほぼ正確な位置情報を示す場合も増えました。

基地局の情報も位置情報特定に役立てるようになったので、それが効果を発揮しているのでしょうか。

バッテリーの持ち

これは非常によくなりました。
弊社で、Smart動態管理という、位置情報を一定間隔で送信するというアプリをリリースしていますが、この新APIに変更したところ、以前は充電なしでは5時間ぐらいしか持たなかったところ、今は18時間ほど持つようになりました。(利用した端末はGalaxy S3a)
これは大きな改善ですよね!

サンプル

Googleさんがサンプルを配ってくれています。
大変ありがたいことですね!
下記からダウンロードできます。

下記のURLの、Dowonload the sampleという青いボタンをクリックして、LocationUpdates.zipをダウンロードします。
http://developer.android.com/training/location/retrieve-current.html

仕組み

以前は

 LocationListener

インターフェースを実装して作っていましたが、今度から

 GooglePlayServicesClient.ConnectionCallbacks,
 GooglePlayServicesClient.OnConnectionFailedListener, 
 LocationListener 

を実装します。

1番目のLocationListenerと2番目のLocationListenerは、名前はほぼ同じですが、中身が違うので、これは注意が必要です!!

旧LocationListenerはandroid.location.LocationListenerですが、
新LocationListenerはcom.google.android.gms.location.LocationListenerです。

私自身はこれにちょっとハマりましたので、みなさんは気をつけてください。

さて、肝心の実装方法です。

Google Play Serviceを利用する新位置情報取得APIについて 実装方法

Google Notebookで情報共有する

Googleツール
業務効率Up

Google Notebookで情報共有する

さて、Google NotebookでWebをメモるでGoogle Notebookを導入したら、簡単な情報共有ができるので、やってみましょう!

簡単な議事録とか、グループ内で共有したいこと、これを使うと至極便利です。

ノートブックを作ったら、右上の「共有オプション」リンクをクリックします。
そして、共有したい相手のメールアドレスを入力し、「設定を保存」をクリックします。
あとは、受け取った相手側で、同じくGoogleアカウントを取得し、Notebookにログインすれば、相手側でも同じノートブックが見れます。

ノートブックごとに共有設定ができるので、これは自分だけが見たい、とかなどの設定もできますね。

By Akiko Goto

Google NotebookでWebをメモる

Googleツール
業務効率Up

Google NotebookでWebをメモる

Webでいい情報があったなーと思った時、いちいち印刷したり、メールでリンクを送ったりしてませんか?

Google Notebookは地味なツールですが、使ってみるとかなり便利!上記のようなことが不要になります。ちなみに無料です。
私自身は手放せないツールです。

  1. 右のページから、Googleにログイン Google Notebookの最初のページ
  2. まずはテスト的に新しいメモを作ってみましょう。左上の「新規作成」というボタンをクリック。最初に出てくるボックスは、タイトル入力画面です。適当に入力して、OKをクリックします。
  3. すると中身の入力になるので、適当にメモります。
  4. 次にいきなりですが、「拡張機能」をダウンロードしましょう。これがないと、Notebookの良さが生かせません。 Google Notebookの拡張機能ダウンロード
  5. 同意してダウンロードをクリックし、ダウンロード&インストールします。
  6. IEの場合、上部にポップアップブロックが出てきてダウンロードが中断されることがありますが、「ブロックを許可」しましょう。
  7. 指示の通りインストールすると、画面の右下にノートのアイコンが出ます。
  8. それをクリックすると、小窓が開いて先ほどのテストメモが出てきます。その小窓にいろいろメモってみましょう。Google Notebookにいちいちいかなくっても、思い立った時にメモをとれるのです。
  9. しかし便利さの真髄はここから!何か適当なWebサイトを開いて、画像やテキストの上で右クリックしてください。一番下に、「メモを追加(Google Notebook)」と出てきます。これをクリックします。
  10. すると、画像も一緒にNotebookに保存がされます。しかも、自動でそのサイトのリンクを記入してくれます。

めっちゃ、便利じゃないですか?[smile] 

  • これは素晴らしい!目からタラコです。 — U田 {2007-08-23 (木) 16:15:02}
    • ええ、本当にいいツールですよね!グーグルさんありがとうw — Akiko Goto {2007-08-23 (木) 18:12:53}

Google Map ドラッグアンドドロップが可能なマーカーを作る

Googleツール
Ajax

Google Map ドラッグアンドドロップが可能なマーカーを作る

マップ上にマーカーがあって、それをドラッグアンドドロップで任意の場所に移動し、その緯度経度を取ってくる方法です。
前後のGoogle Mapの実装は省きます。

 marker = new google.maps.Marker({
 		map : map,
 		position :latlng,
 		icon : icon,
 		draggable:true
 });
 // マーカーをドラッグした場所の緯度経度に更新
 //dragendってtypoかと思いますが、これであっています
 google.maps.event.addListener(marker, "dragend", function(event) { 
          var lat = event.latLng.lat(); 
          var lng = event.latLng.lng(); 
          alert(lat);
        });