3

定期的に場所を取得して、ネットワーク経由で送信しようとしています。それを行う前に、場所を正しく取得していることを確認することが重要だと感じています! そのために、場所を取得して、メッセージを画面に表示する Handler に送信しようとします。私はあちこちを検索し、実際にスタック オーバーフローで非常に便利なコード セグメントを使用しました (どうもありがとうございました!) Android でユーザーの現在の場所を取得する最も簡単で最も堅牢な方法は何ですか?

いくつかのコードを次に示します。

MyLocation (例から):

package com.Locator;

import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

public class MyLocation {
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled=false;
boolean network_enabled=false;

public boolean getLocation(Context context, LocationResult result)
{
    //I use LocationResult callback class to pass location value from MyLocation to user code.
    locationResult=result;
    if(lm==null)
        lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

    //exceptions will be thrown if provider is not permitted.
    try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
    try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}

    //don't start listeners if no provider is enabled
    if(!gps_enabled && !network_enabled)
        return false;

    if(gps_enabled)
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
    if(network_enabled)
        lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
    timer1=new Timer();
    timer1.schedule(new GetLastLocation(), 20000);
    return true;
}

LocationListener locationListenerGps = new LocationListener() {
    public void onLocationChanged(Location location) {
        timer1.cancel();
        locationResult.gotLocation(location);
        lm.removeUpdates(this);
        lm.removeUpdates(locationListenerNetwork);
    }
    public void onProviderDisabled(String provider) {}
    public void onProviderEnabled(String provider) {}
    public void onStatusChanged(String provider, int status, Bundle extras) {}
};

LocationListener locationListenerNetwork = new LocationListener() {
    public void onLocationChanged(Location location) {
        timer1.cancel();
        locationResult.gotLocation(location);
        lm.removeUpdates(this);
        lm.removeUpdates(locationListenerGps);
    }
    public void onProviderDisabled(String provider) {}
    public void onProviderEnabled(String provider) {}
    public void onStatusChanged(String provider, int status, Bundle extras) {}
};

class GetLastLocation extends TimerTask {
    @Override
    public void run() {
         lm.removeUpdates(locationListenerGps);
         lm.removeUpdates(locationListenerNetwork);

         Location net_loc=null, gps_loc=null;
         if(gps_enabled)
             gps_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
         if(network_enabled)
             net_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

         //if there are both values use the latest one
         if(gps_loc!=null && net_loc!=null){
             if(gps_loc.getTime()>net_loc.getTime())
                 locationResult.gotLocation(gps_loc);
             else
                 locationResult.gotLocation(net_loc);
             return;
         }

         if(gps_loc!=null){
             locationResult.gotLocation(gps_loc);
             return;
         }
         if(net_loc!=null){
             locationResult.gotLocation(net_loc);
             return;
         }
         locationResult.gotLocation(null);
    }
}

public static abstract class LocationResult{
    public abstract void gotLocation(Location location);
}
}

このように使用すると、正常に動作します (以下は Main アクティビティ クラスのコードです)。

    MyLocation myLocation = new MyLocation();



    LocationResult locationResult = new LocationResult(){
        @Override
        public void gotLocation(final Location location){
           Message m = new Message();
           m.obj = location.getLongitude() + " " + location.getLattitude();
           threadHandler.sendMessage(m);
        }
    };

ただし、これを定期的に実行したいので、次のようなものがあります (次のコードはメイン アクティビティ クラスにあり、今回は Runnable を実装しています)。

....
new Thread(this).start();
....

public void run() {
    MyLocation myLocation = new MyLocation();



    LocationResult locationResult = new LocationResult(){
        @Override
        public void gotLocation(final Location location){
           Message m = new Message();
           m.obj = "SDFSDF";
           threadHandler.sendMessage(m);
        }
    };

    while(true) {

        myLocation.getLocation(this, locationResult);
        try {
        Thread.sleep(30000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
      }
}
}

注: threadHandler は、次で定義されている MyHandler 型です。

class MyHandler extends Handler{

private TextView threadModifiedText;
public MyHandler(TextView tv) {
    threadModifiedText = tv;
}

 public void handleMessage(Message msg) {
        // whenever the Thread notifies this handler we have
        // only this behavior
        threadModifiedText.setText((CharSequence)msg.obj);
 }
}

Looper.prepare() を呼び出していないスレッドから Handler への書き込みに関するエラーが発生しています。アクティビティとスレッドのさまざまな部分に Looper.prepare() と Looper.loop() を追加しようとしましたが、役に立ちませんでした。run() + sleep() の代わりにタイマーを使用してみました。

後で、スレッド ハンドラーに書き込む代わりに、場所をキューに挿入します。ソケット接続を処理する別のスレッドは、キューが空かどうかをチェックします。要素がある場合、dequeue() して送信します。

アドバイスをお願いします。

4

1 に答える 1

1

あなたが見つけられなかった場合に備えて。ルーパーはしばらくの間外にある必要があり、新しい呼び出しの前に myLocation を再初期化する必要があります。ただし、その場合、 MyLocation クラスのタイマーにより、これが機能しなくなります。したがって、 getLastLocation 部分を削除すると、サービスで正常に機能するはずです。定期的に位置情報を送信したい場合は、正確であることを望み、さらに 30 秒かかってもかまわないので、とにかく悪いアプローチではありません。ただし、gps とネットワークが有効になっていないときに例外がスローされた場合は、何かをしたい (設定を開く) 必要があります。

幸運を。

Looper.prepare();   

while(true) {
    myLocation = new MyLocatiom()
    myLocation.getLocation(this, locationResult);
    try {Thread.sleep(30000);} catch (InterruptedException e) {}

Looper.loop()
  }
于 2011-12-10T18:43:46.543 に答える