在服务中解压缩.zip文件使应用程序冻结,直到它完成解压缩,为什么?

时间:2013-01-07 02:27:38

标签: java android service android-asynctask 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();

}

现在我在这里使用异步任务来调用它:

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

        d.unzip();

        return null;
    }

现在我的问题是,为什么使用异步tsk我的应用程序不会被冻结并且它将保持解压缩让我用按钮取消它,但是使用服务它会使应用程序滞后?我甚至收到一条关于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 个答案:

答案 0 :(得分:3)

服务在UI(主)线程中运行,因此您还需要在那里实现AsyncTask或sepearate Thread方法。

docs什么是服务?

下说出这一切
  

服务不是线程。它本身不是从主线程开始工作的手段(以避免应用程序无响应错误)。

编辑:请注意,如果从后台线程启动服务,该服务仍在主线程中运行。根据这个SO answer。这应该是正确的,因为文档说:

  

实际创建服务组件时,对于其中任何一个   原因,系统实际做的就是实例化   组件并调用其onCreate()和任何其他适当的回调   在主线程上。由服务部门来实现这些   适当的行为,例如创建其中的辅助线程   它做了它的工作。

这最终意味着无论您如何启动服务,都应该始终在Services中实现单独的AsyncTask / Thread方法。

答案 1 :(得分:1)

如果您不需要AsyncTask的onPreExecute()onPostExecute()方法,请尝试在单独的后台线程中运行它,但仍然存在阻止UI线程的操作的问题。

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

简单地从后台线程启动服务并不意味着它将从主UI线程启动。这是它的开始默认值,您必须在服务中创建一个新线程来绕过它。

答案 2 :(得分:1)

扩大A - C的观点: 您需要创建后台线程以从服务中的解压缩文件,因为该服务已创建并在主线程上运行,无论您是否在另一个线程内启动它。

您基本上需要在服务中完成您在服务之外所做的事情(即将'unzip'调用放在AsyncTask中,并执行任务)。

(附录) 使用服务的关键不是创建单独的线程,而是从基于UI的应用程序中拆分耗时的处理。这意味着操作系统可以销毁UI并恢复资源,并且服务仍然在运行。 因此,关于是否在应用程序本身与服务中使用AsyncTask(或线程)的决定实际上是关于该动作是否应该独立于应用程序界面而继续。使用TitaniumBackup恢复应用程序就是一个很好的例子:一旦你开始恢复,就不再需要应用程序UI了。