5

私のコードでは、IntentService位置の更新 (GPS またはネットワークの更新) をリッスンするために を使用しています。これIntentServiceは、イベントを受信したときにトリガーされるためstartService()、任意のアクティビティから開始されます。

public class AddLocationService extends IntentService implements LocationListener {
    /*My code here*/
}

    @Override
protected void onHandleIntent(Intent intent) {
    if(getOldLoc() == null) 
    { 
        //Get a new location
        this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, TIME_INTERVAL_GPS, 0, this);
        this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, TIME_INTERVAL_GPS, 0, this);
        Log.d(AddLocationService.TAG, "Network listener started");

        this.time_start_listening = System.currentTimeMillis();
        mTimerThread mTimerRunnable = new mTimerThread();
        this.timerThread = new Thread(mTimerRunnable);
        this.timerThread.start();
    }
    else    
        /*REUSE OLD LOCATION*/
}

今私の問題は次のとおりです。2つのイベントがこれIntentServiceを開始し、最初のイベントがまだ更新を要求している間に2番目のイベントが開始した場合、2番目のイベントは最初のイベントが完全に終了するまで待機するようにします(場所が見つかるか、タイマースレッドが終了します)。ただし、IntentServiceが 2 回目に実行される (最初のインスタンスがまだ実行されている) ときはいつでも、ログが出力され、並行して実行されていたように実行されます。

ただし、主な目標はIntentServiceそれがシーケンシャルなものであるため、最初の意図が完了するまで2番目の意図を待たなければならないと思いました...

私は何かを誤解しましたか?

4

3 に答える 3

3

onHandleIntent メソッドが実行中のスレッドをブロックしていないように見えるため、すぐに戻り、2 番目のインテントを処理できるようにします。それだけでなく、onHandleIntent が終了するとバックグラウンド スレッドが強制終了される可能性が高いため、LocationManager からそのスレッドへのコールバックが処理される可能性はほとんどありません。

本当に IntentService を使用してインテント キューを管理したい場合は、独自のスレッドでロケーション処理を行い、ロケーション コールバックを待っている間に IntentService スレッドをロケーション スレッドに参加させる必要があります。

アイデアを示すちょっとしたコードを次に示します。

public class TestService extends IntentService {
    private static final String TAG = "TestService";

    private Location mLocation = null;

    public TestService() {
       super(TAG);
    }

    @Override
    public void onHandleIntent(Intent intent) {
        Log.d(TAG, "onHandleIntent");

        if (mLocation == null) {
            Log.d(TAG, "launching location thread");
            LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

            LocationThread thread = new LocationThread(locationManager);
            thread.start();
            try {
                thread.join(10000);
            } catch (InterruptedException e) {
                Log.d(TAG, "timeout");
                return;
            }

            Log.d(TAG, "join finished, loc="+mLocation.toString());
        } else {
             Log.d(TAG, "using existing loc="+mLocation.toString());
        }
    }

    private class LocationThread extends Thread implements LocationListener  {
        private LocationManager locationManager = null;

        public LocationThread(LocationManager locationManager) {
            super("UploaderService-Uploader");
            this.locationManager = locationManager;
        }

        @Override
        public void run() {
            Log.d(TAG, "Thread.run");
            Looper.prepare();
           this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
            this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);

            Looper.loop();
        }

        @Override
        public void onLocationChanged(Location location) {
            // TODO Auto-generated method stub
            Log.d(TAG, "onLocationChanged("+location.toString()+")");
            mLocation = location;
            Looper.myLooper().quit();
         }

         @Override
         public void onProviderDisabled(String arg0) {
         }

         @Override
         public void onProviderEnabled(String arg0) {
         }

         @Override
         public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
         }

   }
}

興味深いのは、(コールバックの処理を可能にするために) スレッドでメッセージ ループを実行する Looper です。

IntentService でこれを行うために必要な労力を考えると、代わりに Service から派生し、独自のインテント キューを管理することを検討する価値があるかもしれません。

于 2011-07-28T22:21:19.870 に答える
2

onHandleIntent はすでに独自のスレッドにあります。そこに作成しないでください(すべきではありません)。それはすべて IntentService によって処理されます。

于 2011-07-28T23:35:25.967 に答える
1

百万に感謝します、それはまさに私が位置要求を処理するために必要だったものです。説明と明確化をありがとう、私はすべてのルーパーの概念にあまり精通していませんでした、今私はそれをよりよく理解しています!

誰かが同じ種類のものを必要とする場合、あなたのロケーションスレッドが自然に停止していない場合(時間の終わり)にスレッドルーパーを停止することを忘れないでください:join(millis)これを追加してonHandleIntent()ください:

                if(thread.isAlive())
                {
                    thread.onThreadStop();
                    try{
                        thread.interrupt();
                    }catch (Exception e) {
                        Log.d(TAG, "Exception on interrupt: " + e.getMessage());
                    }
                }   

thread.join(yourTime)、たとえば、場所の更新が見つからなかった場合でも、一定時間後にスレッドを停止します。そして方法についてonThreadStop()

                /*We remove location updates here and stop the looper*/
                public void onThreadStop()
                {
                    this.locationManager1.removeUpdates(this);
                    handleLocationChange(AddLocationService.this.currentBestLocation);
                    Looper.myLooper().quit();
                }

ただし、このコードを初めて実行したときに2つのインテントが処理されるのを見たと思いましたが、現在は、場所の更新を要求しているときに複数のインテントがある場合、最初のインテントのみが処理されます。私のメソッドonHandleIntent()は正しく実行されているようで、指定された時間後にスレッドを停止し、最後のログ(メソッドの最後のステートメント)を表示しますが、2番目のインテントは実行されません...理由はわかりますか?

于 2011-07-29T12:04:50.673 に答える