2011年2月13日星期日

Interrupting/cancelling threads - Android

SDK Version: 
 M3
threadWhen you run a background operation using a Thread, or AsyncTask in most of the times it is needed to be able to interrupt it.
In lot of cases, when the user starts a sceen in our application, a thread is started in the background, to load its content. Hoever if the user leaves the screen before its loading is complete, the loading process should be interrupted. Even if the loading prosess can not be interrupted immediately, or it would be too mutch troube, it shold detect that the display of the result is no longer needed.
So how do you stop a thread exactly? You can see in the documentation that Thread class has a stop() method. This method offered an "easy" way to interrupt threads in older android versions, by killing the thread. It is deprecated now, do not use it, it may left things in inconstent state, among other problems, so this was an unelegant way.
The methods you can use is Thread.interrupt() and AsyncTask.cancel(), hoewer just calling them wont kill the process, it will be likely just flagged as interrupted, and continue running. You must implement the interrupt yourself!
In most cases the slow background process has a "main loop", so if you check if the process is interrupted in the loop condition. For example a file download is like that. You can check the Treads interrupted flag with its isInterrupted() method:
  1. thread = new Thread() {
  2.   public void run() {
  3.     ...
  4.     while(!isInterrupted() && hasMoreDataToDownload()){
  5.       downloadAndWriteSomeMore();
  6.     }
  7.     if(isInterrupted()){
  8.       deleteThePartiallyDownloadedFile();
  9.     }else{
  10.       callBack();
  11.     }
  12.   }
  13. }
  14. thread.start();
  15. thread.interrupt();
If the process is interrupted, you exit the main loop close files, other sesources properly, do some cleanup if nesessary, for example delete the not needed unfinished file. The callBack() function runs othervise. You may want to send a message here to a Handler to indicate somewhere on the user interface that the process ended sucessfully.
If you dont have such main loop in the thread, for example a slow SQL query is executed, and you can not interrupt the query, you still want to care about isInterrupted() after the query run. If the user alredy left the screen that needed the query result, the threads interrupt should be called, so the thread knows a callBack is not needed, the user interface to hold the result may not even exist by that time.

没有评论:

发表评论