2013-01-07 31 views
1

我實現了與異步任務一起工作的代碼,它的工作原理非常完美,但是如果用戶退出應用程序,它會非常快速地被殺死,所以我決定嘗試使用服務,它完美地工作,但它會使應用程序凍結。解壓縮服務中的.zip文件會導致應用程序凍結,直至完成解壓縮爲止?

因此,這裏是我的解壓縮類:

public class Decompress { 
    private String _zipFile; 
    private String _location; 
    ZipEntry ze = null; 

    public Decompress(String zipFile, String location) { 
     _zipFile = zipFile; 
     _location = location; 

     _dirChecker(""); 
    } 

    public void unzip() { 
     try { 
      FileInputStream fin = new FileInputStream(_zipFile); 
      ZipInputStream zin = new ZipInputStream(fin); 
      while ((ze = zin.getNextEntry()) != null) { 
       //Log.v("Decompress", "Unzipping " + ze.getName()); 

       if(ze.isDirectory()) { 
        _dirChecker(ze.getName()); 
       } else { 
        FileOutputStream fout = new FileOutputStream(_location + ze.getName()); 
        for (int c = zin.read(); c != -1; c = zin.read()) { 
         fout.write(c); 
        } 

        zin.closeEntry(); 
        fout.close(); 
       } 

      } 
      zin.close(); 
     } catch(Exception e) { 
      Log.e("Decompress", "unzip", e); 
     } 

    } 

    private void _dirChecker(String dir) { 
     File f = new File(_location + dir); 

     if(!f.isDirectory()) { 
      f.mkdirs(); 
     } 
    } 
} 

這裏是我的服務電話進行解壓:

@Override 
public void onStart(Intent intent, int startid) 
{ 

    try 
    { 
     zipFile = intent.getStringExtra("zipFile"); 
     zipLocation = intent.getStringExtra("unzipLocation"); 
     String fileS = intent.getStringExtra("file"); 
     file = new File(fileS); 
     fin = new FileInputStream(zipFile); 
     zin = new ZipInputStream(fin); 

     while (zin.getNextEntry() != null) { 
      numFiles++; 
     } 
    } 
    catch (FileNotFoundException e) 
    {} 
    catch (IOException e) 
    {} 

    d = new Decompress(zipFile, zipLocation); 
    d.unzip(); 

} 

現在,這裏就是我ussed與異步任務來調用它:

@Override 
    protected Void doInBackground(Void... params) { 

     d.unzip(); 

     return null; 
    } 

現在我的問題是,爲什麼與異步tsk我的應用程序不凍結,它會繼續unzipping讓我取消它與一個按鈕,但與服務,它使應用程序滯後?我甚至收到一條關於MyApp沒有迴應的消息,你想關閉它嗎?

編輯:我的服務呼叫的開始

@Override 
    protected Void doInBackground(Void... params) { 

     Intent intent = new Intent(DownloadFiles.this, MyService.class); 
     String unzipLocation = Environment.getExternalStorageDirectory().toString()+"/Android/data/"; 
     String zipFile = Environment.getExternalStorageDirectory().toString()+"/Android/data/test.zip"; 
     intent.putExtra("zipFile", zipFile); 
     intent.putExtra("unzipLocation", unzipLocation); 
     intent.putExtra("file", Environment.getExternalStorageDirectory().toString()+"/Android/data/"); 
     startService(intent); 

     try { 
      FileInputStream fin = new FileInputStream(zipFile); 
      ZipInputStream zin = new ZipInputStream(fin); 

      while (zin.getNextEntry() != null) { 
       numFiles++; 
       } 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return null; 
    } 

回答

3

服務運行在UI(主)線程,所以你需要實現的AsyncTask或sepearate線程的方法也有。

docs根據全部說明什麼是服務?

服務不是線程。它不是一種自己的方式來處理主線程(以避免應用程序不響應錯誤)。

編輯:請注意,如果您從後臺線程啓動服務,該服務仍在主線程中運行。按照這個SO answer。這也解釋了該文件說:

當實際創建一個服務組件,用於任一 原因,所有的系統實際上做的是實例化 組件並調用它的onCreate()和其他任何在主線程上適當回調 。這是由服務實施這些與 適當的行爲,如創建一個輔助線程,其中 它的工作。

這最終意味着無論您如何啓動服務,您都應始終在服務中實施單獨的AsyncTask/Thread方法。

+0

我確實在同步任務中添加了服務調用,抱歉忘了添加它。將編輯我的OP。 –

+0

OP編輯,服務電話 –

+0

@RotaryHeart我更新了我的答案。長話短說,即使AsynTask啓動了它,服務仍在主線程中運行。 –

1

如果您不需要AsyncTask的onPreExecute()onPostExecute()方法,請嘗試在單獨的後臺線程中運行它,但仍然會阻塞UI線程的操作。

Thread t = new Thread() { 
    public void run() { 
     d = new Decompress(zipFile, zipLocation); 
     d.unzip(); 
    } 
}; 
t.start(); 

簡單地從後臺線程啓動服務並不意味着它將從主UI線程開始。這是它啓動的默認設置,並且您必須在服務中創建一個新線程才能避開它。

+0

感謝您的這個例子:) –

1

擴展在A - C'S點: 您需要創建後臺線程從解壓縮文件中的服務內,因爲在創建服務,並運行在主線程,不管你啓動另一個線程內或不。

你基本上需要在服務中完成你在服務之外完成的工作(即把'unzip'調用放到AsyncTask中,然後執行任務)。

(附錄) 使用服務的目的不是創建單獨的線程,而是要從基於UI的應用程序中分離耗時的處理。這意味着用戶界面可以被操作系統銷燬並且資源被恢復,並且服務仍在運行。 因此,關於是否在應用程序本身內使用AsyncTask(或線程)與在服務內使用AsyncTask(或線程)的決定實際上是關於應用程序是否應該獨立於應用程序接口繼續。使用TitaniumBackup恢復應用程序就是一個很好的例子:一旦你開始了恢復,應用程序UI就不再需要了。

+0

未來版本的完美信息:) –