IntentService:如何正确入队?

时间:2011-07-28 22:13:12

标签: android service android-intent intentservice

在我的代码中,我使用IntentService来收听位置更新(GPS或网络更新),并在收到事件时触发此IntentService,因此它以{{ 1}}来自任何活动。

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*/ } 而第二个事件启动它而第一个仍在请求更新时,我希望第二个事件等到第一个事件完全结束(找到位置) OR计时器线程完成)。 但是,每当第二次执行IntentService(第一个实例仍在运行)时,它就会打印出日志并执行并行执行。

但是我认为IntentService的主要目标是它是顺序的,所以第二个意图必须等到第一个完成...

我是否想念一些东西?

3 个答案:

答案 0 :(得分:3)

看来你的onHandleIntent方法没有阻塞它正在执行的线程,所以它会快速返回并允许处理第二个意图。不仅如此,从LocationManager到该线程的任何回调都不太可能被处理,因为当onHandleIntent完成后,后台线程可能会被杀死。

如果您真的想使用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执行此操作所需的工作,可能值得研究从服务派生而不是管理您自己的意图队列。

答案 1 :(得分:2)

onHandleIntent已经在它自己的线程中了。你不(不应该)在那里创建。这一切都由IntentService为您处理。

答案 2 :(得分:1)

万分感谢,这正是我处理位置请求所需要的。 感谢您的解释,并为我说清楚,我对所有的looper概念并不是很熟悉,现在我更了解它!

如果某人需要相同类型的东西,请不要忘记如果您的位置线程没有自然停止(join(millis)上的时间结束),请通过在{{1}中添加此内容来停止线程循环器}:

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(); } 似乎正确执行,在指定的时间后停止线程,甚至显示最后一个Log(方法的最后一个语句),但第二个intent没有执行... 你知道为什么吗?