繁体   English   中英

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

[英]Decompressing .zip file in service makes app freeze until it finish decompressing, why?

我实现了与异步任务一起使用的代码,并且可以完美运行,但是如果用户退出应用程序,它将很快被杀死,因此我决定通过服务尝试它,它可以完美运行,但是会使应用程序冻结。

所以这是我的解压缩类:

    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;
    }

服务运行在UI(主)线程中,因此您也需要在其中实现AsyncTask或单独的线程方法。

文档在“ 什么是服务”下说明了一切

服务不是线程。 它本身并不是在主线程之外工作的一种方式(以避免Application Not Responding错误)。

编辑:请注意,如果您从后台线程启动服务,则该服务仍在主线程中运行。 按照这个SO 答案 正如文档所说,这应该是有道理的:

由于这些原因之一,当实际上创建Service组件时,系统实际上所做的就是实例化该组件并在主线程上调用其onCreate()和任何其他适当的回调。 服务必须以适当的行为来实现这些目的,例如创建一个辅助线程来执行其工作。

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

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

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

仅从后台线程启动服务并不意味着它将从主UI线程启动。 这是启动时的默认设置,您必须在Service中创建一个新线程来解决它。

扩展到A–C的观点:您需要创建后台线程来从服务内部解压缩文件,因为该服务是在主线程上创建并运行的,而不管您是否在另一个线程中启动它。

基本上,您需要在服务中执行与在服务之外所做的完全相同的操作(即,将“ unzip”调用放在AsyncTask中,然后执行任务)。

(附录)使用服务的目的不是创建单独的线程,而是将耗时的处理与基于UI的应用程序分开。 这意味着UI可能会被OS破坏并恢复资源,并且在服务仍在运行的同时。 因此,关于在应用程序本身内部还是在服务内部使用AsyncTask(或线程)的决定实际上是关于操作是否应独立于应用程序界面而继续进行。 使用TitaniumBackup还原应用程序就是一个很好的例子:开始还原后,实际上不再需要应用程序UI。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM