1

非同期タスクで動作するコードを実装しましたが、完全に動作しますが、ユーザーがアプリを終了すると非常に速く殺されるため、サービスで試してみることにしました。完全に動作しますが、アプリがフリーズします。

だからここに私の解凍クラスがあります:

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

unzip のサービス コールは次のとおりです。

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

3 に答える 3

3

サービスは UI (メイン) スレッドで実行されるため、そこでも AsyncTask または個別のスレッド アプローチを実装する必要があります。

ドキュメント、サービスとは何ですか

サービスはスレッドではありません。それ自体は、メイン スレッドから離れて作業を行う手段ではありません (アプリケーションが応答しないエラーを回避するため)。

編集: バックグラウンド スレッドからサービスを開始する場合、サービスは引き続きメイン スレッドで実行されていることに注意してください。この SO answerに従って。ドキュメントが言うように、これは理にかなっています:

サービス コンポーネントが実際に作成されるとき、これらの理由のいずれかにより、システムが実際に行うことは、コンポーネントをインスタンス化し、その onCreate() およびメイン スレッドで他の適切なコールバックを呼び出すことだけです。適切な動作でこれらを実装するのは、サービス次第です。たとえば、作業を行うセカンダリ スレッドを作成するなどです。

これは最終的に、サービスを開始する方法に関係なく、サービスにも個別の AsyncTask/Thread アプローチを常に実装する必要があることを意味します。

于 2013-01-07T02:34:28.233 に答える
1

A--C のポイントの拡張:サービスは、別のスレッド内で開始するかどうかに関係なく、メイン スレッドで作成および実行されるため、サービスからファイルを解凍するバックグラウンド スレッドを作成する必要があります。

基本的に、サービス外で行ったことをサービス内で行う必要があります (つまり、「unzip」呼び出しを AsyncTask 内に配置し、タスクを実行します)。

(追記) サービスを利用するポイントは、別スレッドを作るのではなく、時間のかかる処理をUIベースのアプリから切り離すことです。これは、UI が OS によって破壊され、リソースが回復され、サービスがまだ実行されている間ずっと可能であることを意味します。したがって、アプリ自体とサービス内で AsyncTask (またはスレッド) を使用するかどうかの決定は、アプリ インターフェイスとは無関係にアクションを続行するかどうかにかかっています。TitaniumBackup を使用したアプリの復元はその好例です。復元を開始すると、アプリの UI は不要になります。

于 2013-01-07T02:52:45.497 に答える
1

AsyncTask のメソッドonPreExecute()とメソッドが必要ない場合は、別のバックグラウンド スレッドで実行してみてください。ただし、操作が UI スレッドをブロックするという問題が残っています。onPostExecute()

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

バックグラウンド スレッドから単にサービスを開始しても、メインの UI スレッドからサービスが開始されるわけではありません。これが開始時のデフォルトであり、それを回避するにはサービス内に新しいスレッドを作成する必要があります。

于 2013-01-07T02:43:16.473 に答える