问题
In my preference screen, I want to start a service to download files from the internet when one of the preference is being clicked. If the service is already running (downloading files), then the service should be stopped (cancel download).
public class Setting extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
downloadPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference pref) {
if (DownloadService.isRunning) {
Setting.this.stopService(new Intent(Setting.this,
DownloadService.class));
} else {
Setting.this.startService(new Intent(Setting.this,
DownloadService.class));
}
return false;
}
});
}
}
The service class:
public class DownloadService extends IntentService {
public static final int DOWNLOAD_SUCCESS = 0;
public static final int DOWNLOAD_FAIL = 1;
public static final int DOWNLOAD_CANCELLED = 2;
public static final int SERVER_FAIL = 3;
public static boolean isRunning = false;
private int result;
public DownloadService() {
super("DownloadService");
}
@Override
public void onCreate() {
super.onCreate();
isRunning = true;
}
@Override
protected void onHandleIntent(Intent intent) {
if (NetworkStateUtils.isInternetConnected(getApplicationContext()))
result = downloadFiles(getApplicationContext());
}
@Override
public void onDestroy() {
super.onDestroy();
switch (result) {
case DOWNLOAD_SUCCESS:
Toast.makeText(getApplicationContext(), R.string.download_finished,
Toast.LENGTH_SHORT).show();
break;
case DOWNLOAD_CANCELLED:
Toast.makeText(getApplicationContext(), R.string.download_canceled,
Toast.LENGTH_SHORT).show();
break;
case DOWNLOAD_FAIL:
Toast.makeText(getApplicationContext(), R.string.download_failed,
Toast.LENGTH_SHORT).show();
break;
}
isRunning = false;
}
}
This service is meant to run until download has finished. The function downloadFiles()
uses no AsyncTask
. It saves the HttpURLConnection
with an FileOutputStream
directly.
The service started correctly when I click the preference. Now the problem is, when I click to stop the service with stopService()
, DownloadService
triggered onDestroy()
immediately; however according to logs, onHandleIntent()
is still running becasue I can still see HTTP requests continuously. Is this because Service
runs in a thread itself, or am I doing something wrong? How can I ensure that everything in onHandleIntent()
stops immediately (or at least able to stop) when stopService()
is being called?
回答1:
Finally figured out how to make it work.
As I stated in my question, somehow onHandleIntent() will create a thread to do the job. So even when the service itself is destoryed, the thread is still running. I achieved my goal by adding a global variable
private static boolean isStopped = false;
to DownloadService
class.
In order to cancel my service, instead of calling
Setting.this.stopService(new Intent(Setting.this, DownloadService.class));
just set DownloadService.isStopped = true
.
Finally, while doing things in onHandleIntent()
, check this boolean periodically to see if it should stop downloading. If isStopped = true
, return immediately and the service will stop itself.
Hope this helps someone who come across this problem too. And thanks for your time reading this question.
回答2:
It has a separate thread to do work, and depending on what it is doing it might not be possible to stop it immediately. If it is blocking on I/O, interrupting it will likely have no effect.
来源:https://stackoverflow.com/questions/12927307/intentservice-onhandleintent-still-running-after-ondestroy-fired