[android-group-japan: 3932] GPS位置情報の取得について

3,701 views
Skip to first unread message

佐藤寛己

unread,
Apr 27, 2010, 4:16:53 AM4/27/10

はじめまして。
GPS位置情報の取得周りで困っています。

Activity側から、requestLocationUpdatesでGPS取得を有効にし(LocationManager.GPS_PROVIDERを使っています。)
さらに3つのServiceを立ち上げ、Activityをfinishさせてサービスのみが起動している。

こういったアプリを製作しているのですが、GPSの取得がうまくいきません。
位置情報が欲しいときにService上で、getLastKnownLocation(LocationManager.GPS_PROVIDER)
を使用して位置情報を取得しているのですが、しばしばGPSが更新されなくなる現象がおきてしまいます。
具体的にいうと、位置情報が一切動かなくなる(端末の位置は動いているにも関わらず)というものです。

この状況を回避する有効な手立てをご存知の方がいましたら、ぜひご教授お願い申し上げます。

以下ソースです。

BaseActivity.java(Activityクラス)
//GPSを有効にする。
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,0,BaseActivity.this);

BaseService.java(Serviceクラス。getCurrentLocationで位置情報を取得しています。)

  public Location getCurrentLocation(){

    //GPS位置情報の取得
    LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
    Location loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

    return loc;
  }


IPC 佐藤 寛己
 

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループに投稿するには、[email protected] にメールを送信してください。
このグループから退会するには、[email protected] にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。

Satoru Isomoto

unread,
Apr 27, 2010, 7:27:17 AM4/27/10
IPC佐藤さん

いそもとです。

記憶が定かではありませんので間違えているかもしれませんが、
佐藤さんが実装しようとしているServiceクラスにLocationListener をimplements して、
onLocationChanged()をOverrideすることで変化した際の
緯度経度が取得出来たかと思いますが、如何でしょうか?

少なくとも、getLastKnownLocation()では、変化した際の緯度経度ではなく、
直近に測位した値となるので、意図した緯度経度は取得できないと思います。

参考になれば幸いです。

2010å¹´4月27æ—¥17:16 佐藤寛己 <[email protected]>:

awwa

unread,
Apr 27, 2010, 8:00:19 AM4/27/10
あわです。

外してるかもしれませんが、
requestLocationUpdates()の引数のminTimeはいろいろ値をいじって試してみたことはありますか?
2000くらいにしてみて試してみるとうまくいくかも。

2010å¹´4月27æ—¥17:16 佐藤寛己 <[email protected]>:

寛己 佐藤

unread,
Apr 28, 2010, 1:20:52 AM4/28/10
to 日本Androidの会
佐藤です。
いそもとさん、お返事ありがとうございます。

このアプリで使っているGPS位置情報取得は、定期的に端末の位置を取得する
というものなので、移動していても、していなくても位置情報を返したかったため
任意のタイミングでgetLastKnownLocationを使って位置情報を取得していました。

>変化した際の緯度経度ではなく、 直近に測位した値となるので、

getLastKnownLocationを使うと、
最後に取得したGPS位置情報=最後に変化したGPS位置情報
が返って来ると考えていたのですが、私の認識違いでしょうか。

getLastKnownLocationでGPS位置情報は取れているのですが、
例えば、10回目まではGPS位置情報が正確にとれたのだけれども、
11回目以降が取れていない。
画面上部のGPSアイコンも同時に消えてしまっている。
こういった現象が起きています。

私の言葉足らずで申し訳なかったです。


On 4月27æ—¥, 午後8:27, Satoru Isomoto <[email protected]> wrote:
> IPC佐藤さん
>
> いそもとです。
>
> 記憶が定かではありませんので間違えているかもしれませんが、
> 佐藤さんが実装しようとしているServiceクラスにLocationListener をimplements して、
> onLocationChanged()をOverrideすることで変化した際の
> 緯度経度が取得出来たかと思いますが、如何でしょうか?
>
> 少なくとも、getLastKnownLocation()では、変化した際の緯度経度ではなく、
> 直近に測位した値となるので、意図した緯度経度は取得できないと思います。
>
> 参考になれば幸いです。
>
> 2010å¹´4月27æ—¥17:16 佐藤寛己 <[email protected]>:
>
>
>
>
>
> > はじめまして。
> > GPS位置情報の取得周りで困っています。
>
> > Activity側から、requestLocationUpdatesでGPS取得を有効にし(LocationManager.GPS_PROVIDERを-使っています。)
> 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

Satoru Isomoto

unread,
Apr 28, 2010, 3:23:24 AM4/28/10
佐藤さん

いそもとです。

Serviceは永続的に起動していることが保証されているものでは
ありませんので、頻繁に殺されます。。。
佐藤さんが取得しようとしているタイミングでサービスが動いていない可能性が高いと思います。

Serviceの再起動(?)の処理が必要の様な気がしますが、
もっと有識者の方の手助けが欲しいところですね。





2010å¹´4月28æ—¥14:20 寛己 佐藤 <[email protected]>:

寛己 佐藤

unread,
Apr 28, 2010, 3:31:59 AM4/28/10
to 日本Androidの会
さとうです。
あわさん、お返事ありがとうございます。

requestLocationUpdatesのminTimeをいじってみたのですが、前より安定?するような気もしました。
ですが、不特定のタイミングでGPS更新が無効(端末上部のGPS受信マークが消える)になってしまいます。
getLastKnownLocationでGPS位置情報を取得しておりますので、
GPS更新が無効になったあとは、同じ位置を返し続けるという現象がやはり起きてしまいます。

電池の消費量を抑えるという観点からも、minTimeの設定は必要だと思いました。


On 4月27æ—¥, 午後9:00, awwa <[email protected]> wrote:
> あわです。
>
> 外してるかもしれませんが、
> requestLocationUpdates()の引数のminTimeはいろいろ値をいじって試してみたことはありますか?
> 2000くらいにしてみて試してみるとうまくいくかも。
>
> 2010å¹´4月27æ—¥17:16 佐藤寛己 <[email protected]>:
>
>
>
>
>
> > はじめまして。
> > GPS位置情報の取得周りで困っています。
>
> > Activity側から、requestLocationUpdatesでGPS取得を有効にし(LocationManager.GPS_PROVIDERを-使っています。)
> > このグループから退会するには、[email protected]<android-gro-up-japan%[email protected]>にメールを送信してください。
> > 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。
>
> --
> このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> このグループに投稿するには、[email protected] にメールを送信してください。
> このグループから退会するには、[email protected] にメールを送信してください。
> 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

Ishikawa Hiromi

unread,
Apr 28, 2010, 3:51:23 AM4/28/10
佐藤さん

はじめまして、石川と申します。

getLastKnownLocation() は、地図の初期化などとりあえず不正確でもいいので現在地を取得したいような場合に使用するものです。
現在地を定期的に取得したい場合は、いそもとさんも書かれてますが、LocationListner を implement させたクラスを
作成し(もちろんBaseActivity クラス自身が implement しているのであればそれで構いません)、そのクラスの
onLocationChanged()
メソッドで取得します。
ただし、requestLocationUpdates()
メソッドが呼ばれるタイミングは不定期なので、定期的に取りたいのであれば、onLocationChanged()
内では、インスタンスのフィールドに緯度・経度を保存するだけにし、値の取得は自分の好きなタイミングで保存した値を参照するという形にする
のが普通です。
例えば、以下のようになります。

==================== ここからサンプル ========================
public class A extends Activity implements LocationListener {

private LocationManager loc_manager;
private Location loc;
private Timer timer = new Timer();

@Override
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.guidemap);

// ロケーションサービス
loc_manager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);

scheduleTask();
}

// 30秒後に現在値の緯度と経度をトースト表示する
public void scheduleTask() {
TimerTask task = new TimerTask() {
@Override
public void run() {
Toast.makeText(A.this, String.format("緯度:%f, 経度:%f",
loc.getLatitude(), loc.getLongitude()), Toast.LENGTH_SHORT).show();
scheduleTask();
}
};

// 30秒後にタイマー設定
timer.schedule(task, 30000);
}

@Override
protected void onResume() {
super.onResume();
// ロケーションリスナを登録する
// 一応イベントを発生させる最小時間間隔と最小移動距離を指定できるが、
// あくまでバッテリー節約のための参考にするだけなので、この時間間隔や移動距離
// で必ず通知されるわけではない
loc_manager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, // GPS を指定
60, // ミリ秒単位の最小通知時間間隔
10, // メートル単位の最小通知距離間隔
this // リスナインスタンス
);
}

@Override
protected void onPause() {
super.onPause();
loc_manager.removeUpdates(this);
}


@Override
public void onLocationChanged(Location location) {
loc = location;
}

@Override
public void onProviderDisabled(String provider) {
}

@Override
public void onProviderEnabled(String provider) {
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}




2010å¹´4月28æ—¥14:20 寛己 佐藤 <[email protected]>:

Ishikawa Hiromi

unread,
Apr 28, 2010, 3:54:57 AM4/28/10
石川です。
ちょっと間違ってました。

× requestLocationUpdates() メソッドが呼ばれるタイミングは不定期なので、…
◯ onLocationChanged()メソッドのが呼ばれるタイミングは不定期なので、…

です。

寛己 佐藤

unread,
Apr 28, 2010, 4:18:26 AM4/28/10
to 日本Androidの会
佐藤です。
いそもとさん、度々ありがとうございます。
恐らく、サービスは動いていると思うのです。
確証があるわけではないので、以下の流れとソースの一部を載せておきます。


Activity側で、下記ソースのstartService()を呼び出して
3つのサービスを起動し、requestLocationUpdatesでGPS更新を取得します。
各々の処理自体はできているのですが(Serviceが動いている状態)
GPSだけ更新できていないという状態です。

また、GPS起動中に下記ソースのstopService()を呼び出して
3つのサービスを停止して、removeUpdatesでGPS更新を止める。
この場合は、Serviceは3つとも停止されるのですが、
GPS更新が生きてしまっています。(端末上のGPSマークが消えない)

処理の流れとしては、
1.Activityでボタン操作を行い、startService()が実行されることにより
GPS取得を有効にし、Serviceを有効にし、Activityをfinish()して画面を破棄します。
2.Serviceがバックグラウンドで処理を行います。
3.アイコンから再びアプリを起動すると、再びActivityが表示されます。
4.ここでボタン操作を行うと、stopService()が処理されて今まで動いていたServiceが停止されます。

現在の問題点として、
2のServiceが処理を行っている間に、不定期にGPS更新が止まってしまう。
4のstopServiceを呼び出した際に、GPS更新が生きてしまっている。(端末上のGPSマークが消えない)

以下ソースです。

BaseActivity.java
(Activityの親クラスを独自で定義したクラスです)

protected void startService() {

//設定マスタ読み出し
SettingsDto settingsDto = mSettingsDto;

//定期通知メールフラグがONであれば定期メール配信サービスを起動する。
if
(CodeUtil.COMMON_FLAG_ON.equals(settingsDto.getRegularMailFlg()) ==
true) {

//メール配信サービス起動
PendingIntent regularMailIntent = PendingIntent.getService(this,
0,
new Intent(getApplicationContext(),
RegularMailService.class), 0);
AlarmManager regularAlarm = (AlarmManager)
getSystemService(Context.ALARM_SERVICE);

// 次回起動までの時間
int intervalRegularTime = REGULAR_MAIL_CYCLE_TIME_UNIT
* Integer.valueOf(settingsDto.getRegularMailCycle());

// 設定値の定期メール配信で定義したタイミングでサービス呼び出し
regularAlarm.setRepeating(AlarmManager.RTC,
System.currentTimeMillis()
+ intervalRegularTime, intervalRegularTime,
regularMailIntent);

}

//着信通知メールフラグがOnであれば着信通知配信サービスを起動する。
if(CodeUtil.COMMON_FLAG_ON.equals(settingsDto.getTelResponseFlg()))
{

//通話状態取得サービス起動
Intent telIntent = new
Intent(getApplicationContext(),TelephoneService.class);
telIntent.putExtra("type", "start");
super.startService(telIntent);

}

//GPSログフラグがOnであればGPS取得サービスを起動する。
if(CodeUtil.COMMON_FLAG_ON.equals(settingsDto.getGpsResponseFlg()))
{

//GPSログ取得サービス起動
PendingIntent mapIntent = PendingIntent.getService(this, 0,
new Intent(getApplicationContext(), MapService.class), 0);
AlarmManager gpsLogAlarm = (AlarmManager)
getSystemService(Context.ALARM_SERVICE);

// 次回起動までの時間
int intervalMapTime = MAP_CYCLE_TIME_UNIT
* Integer.valueOf(settingsDto.getGpsLogPreservationCycle());

// 設定値のGPSログ取得間隔で定義したタイミングでサービス呼び出し
gpsLogAlarm.setRepeating(AlarmManager.RTC,
System.currentTimeMillis()
+ intervalMapTime, intervalMapTime, mapIntent);

}

//参照を消す
settingsDto = null;

//------------------------------
//サービスマスタの起動フラグをON
//------------------------------
// Dtoから読み出し
ServiceDto serviceDto = mServiceDto;

//起動フラグをONに更新
serviceDto.setStartFlg(CodeUtil.COMMON_FLAG_ON);
//サービスマスタへ更新
sServiceDao.update(serviceDto);
//メンバDtoを最新状態に更新
mServiceDto = serviceDto;

//参照を消す
serviceDto = null;

//------------------------------
//GPS更新を有効にする
//------------------------------

//ロケーションマネージャを取得。
LocationManager locationManager =
(LocationManager)getSystemService(Context.LOCATION_SERVICE);
//GPS更新を有効にする。

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
2000,0,BaseActivity.this);

return;
}


protected void stopService() {

//------------------------------
//定期メール配信サービス停止処理
//------------------------------
PendingIntent regularMailIntent = PendingIntent.getService(this,
0,
new Intent(getApplicationContext(), RegularMailService.class),
0);
AlarmManager am = (AlarmManager)
getSystemService(Context.ALARM_SERVICE);
am.cancel(regularMailIntent);

//------------------------------
//通話状態取得サービス停止処理
//------------------------------
Intent telIntent = new Intent(getApplicationContext(),
TelephoneService.class);
telIntent.putExtra("type", "stop");
super.stopService(telIntent);

//------------------------------
//GPS取得サービス停止処理
//------------------------------
PendingIntent mapIntent = PendingIntent.getService(this, 0,
new Intent(getApplicationContext(), MapService.class), 0);
AlarmManager am2 = (AlarmManager)
getSystemService(Context.ALARM_SERVICE);
am2.cancel(mapIntent);

//------------------------------
//サービスマスタの起動フラグをOFF
//------------------------------
// Dtoから読み出し
ServiceDto serviceDto = mServiceDto;

//起動フラグをONに更新
serviceDto.setStartFlg(CodeUtil.COMMON_FLAG_OFF);
//サービスマスタへ更新
sServiceDao.update(serviceDto);
//メンバDtoを最新状態に更新
mServiceDto = serviceDto;

//------------------------------
//GPS更新を無効にする
//------------------------------
//ロケーションマネージャを取得。
LocationManager locationManager =
(LocationManager)getSystemService(Context.LOCATION_SERVICE);
//GPS更新を無効にする。
locationManager.removeUpdates(BaseActivity.this);

return;
}


On 4月28æ—¥, 午後4:23, Satoru Isomoto <[email protected]> wrote:
> 佐藤さん
>
> いそもとです。
>
> Serviceは永続的に起動していることが保証されているものでは
> ありませんので、頻繁に殺されます。。。
> 佐藤さんが取得しようとしているタイミングでサービスが動いていない可能性が高いと思います。
>
> Serviceの再起動(?)の処理が必要の様な気がしますが、
> もっと有識者の方の手助けが欲しいところですね。
>
> 2010å¹´4月28æ—¥14:20 寛己 佐藤 <[email protected]>:
> >> > Activity側から、requestLocationUpdatesでGPS取得を有効にし(LocationManager.GPS_PROVIDERを--使っています。)

寛己 佐藤

unread,
Apr 28, 2010, 6:05:58 AM4/28/10
to 日本Androidの会
佐藤です。
石川さん、お返事ありがとうございます。

定期的に位置情報を取得する場合用に準備されたメソッドがonLocationChangedに当たるのですね。
私が製作中のアプリは、Activityを破棄した状態(使わない状態?)でサービスのみ動いているというものになるのと、
GPS位置情報が必要なのが3つのサービスでして、
2つのサービスは決まった時間毎に起動して固定処理を行う、1つのサービスはつきっぱなし、というものなので
位置情報を取り続けるサービスを4つ目のサービスとして作って
必要なときに各サービスへ値を引き渡せばいいのかな・・・と思いながら考えています。

もしかしたら相当的外れなことを言っているかもしれないですね。
> 2010å¹´4月28æ—¥14:20 寛己 佐藤 <[email protected]>:
> >> > Activity側から、requestLocationUpdatesでGPS取得を有効にし(LocationManager.GPS_PROVIDERを--使っています。)

Ishikawa Hiromi

unread,
May 11, 2010, 12:15:01 AM5/11/10
佐藤さん

石川です。
サービスだったんですね。
よく読まずにレスしてしまいました。申し訳ありません。
サービスに関しては、作った事ないので自身ないのですが、
requestLocationUpdates() に引数違いの

public void requestLocationUpdates (String provider, long minTime, float minDistance, PendingIntent intent)


というのがあるようです。
これを使えば、適切なタイミングで呼び起こしてくれるのではないでしょうか?
見当はずれだったらごめんなさい。


2010å¹´4月28æ—¥19:05 寛己 佐藤 <[email protected]>:
Reply all
Reply to author
Forward
0 new messages