IntentService:如何正确入队?
Posted
技术标签:
【中文标题】IntentService:如何正确入队?【英文标题】:IntentService : How to enqueue correctly? 【发布时间】:2011-10-15 12:52:04 【问题描述】:在我的代码中,我使用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*/
现在我的问题是:当两个事件启动 IntentService
并且第二个事件启动它而第一个事件仍在请求更新时,我希望第二个事件等到第一个事件完全完成(找到位置或计时器线程完成)。
但是,每当第二次执行 IntentService
时(第一个实例仍在运行),它会打印日志并按照并行执行的方式执行。
但是我认为IntentService
的主要目标是它是连续的,所以第二个意图必须等到第一个意图完成...
我是不是误会了什么?
【问题讨论】:
【参考方案1】:您的 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 执行此操作所需的工作量,可能值得研究从 Service 派生并管理您自己的意图队列。
【讨论】:
嘿@Rob,感谢您的回复。当您说onHandleIntent
方法没有阻塞线程时,您能否更具体一点?我应该怎么做才能阻止它?从另一个活动创建意图时与标志有关还是我应该在 onHandleIntent()
方法中做的事情?
编辑:我想我明白你的意思:我的 IntentService 在仍然请求更新的同时返回。我怎样才能阻止它。两人wait() - notify()
会是个好主意吗?
有点,我已经更新了我的答案,提供了有关如何修复它的更多信息
也可以直接在 IntentService 后台线程上使用 Looper,但我有点紧张,因为我不确定它是否会对 IntentService 管理排队。【参考方案2】:
onHandleIntent 已经在它自己的线程中了。你不(不应该)在那里创作。这一切都由 IntentService 为您处理。
【讨论】:
【参考方案3】:感谢一百万,这正是我处理位置请求所需要的。 谢谢你的解释,让我明白,我对所有的looper概念都不是很熟悉,现在我更好地理解了!
如果有人需要同样的东西,如果您的位置线程没有自然停止(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();
但是,我认为我在第一次运行此代码时看到了我的两个意图被处理,但现在当我有多个意图同时仍然请求位置更新时,只有第一个被处理。
我的方法onHandleIntent()
似乎执行正确,在指定的时间后停止线程,甚至显示最后一个日志(方法的最后一条语句),但第二个意图没有执行......
你知道为什么吗?
【讨论】:
经过几次测试后,我注意到只有在某些情况下(当我调用thread.interrupt()
,即时间到期时)线程仍在运行,这可能就是为什么下一个意图不是治疗。但是,当线程正常完成时,线程确实完全停止(thread.isAlive()
返回 false)并且我的下一个意图被发送。所以我的问题是:如何正确停止我的线程,和/或为什么在使用thread.interrupt()
时它没有停止??以上是关于IntentService:如何正确入队?的主要内容,如果未能解决你的问题,请参考以下文章
LocalBroadcastReceiver + IntentService 是正确的做法吗?
在 IntentService 和 AsyncTask (Android) 之间使用共享代码时,领域“从不正确的线程访问”错误