1

私のAndroidアプリケーションでは、特定のアクティビティで、ビューを実際に表示せずにスクリーンショットを作成する必要があります。ビューを膨らませてビットマップとして保存することで、これを達成することに成功しました。ただし、一部のシナリオでは、これらのビットマップの数が十分に多く、作成に多くの時間がかかります。そのため、電話の UI が応答しなくなります。このプロセス全体をバックグラウンドで実行する方法はありますか? 私はすでに非同期タスクで実装しようとしましたが、非同期タスクでビューを膨らませることが許可されていないため、機能しません。

どんな提案でも大歓迎です。

4

2 に答える 2

2

AsyncTask doBackground メソッドは別のスレッドで機能します。これが、ビューを膨らませることができない理由です。

まず、レイアウトが 1 つか複数か。たくさんある場合は、以下を試してください。

私はこれをテストしていません。あなたのためだけのサンプルです。

public class Task extends AsyncTask<Void, Integer, Void>
    {
        private ArrayList<Integer> layoutIds;
        private View currentView;
        private LayoutInflater inflater;
        private Object lock = new Object();

        public Task(Context context) {
            super();
            inflater = LayoutInflater.from(context);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

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

            Bitmap temp;

            for (int i = 0; i < layoutIds.size(); i++) {

                temp = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
                Canvas canvas = new Canvas(temp);

                synchronized (lock) {
                    publishProgress(i);

                    try {
                        // Wait for the UI Thread to inflate the layout.
                        lock.wait();
                    }
                    catch (InterruptedException e) {

                    }
                }

                currentView.draw(canvas);

                // Now save this bitmap
                try {
                    FileOutputStream stream = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "File_" + i + ".png"));
                    temp.compress(Bitmap.CompressFormat.PNG, 100, stream);
                    stream.flush();
                    stream.close();
                } catch (Exception e) {

                }
                finally
                {
                    if(temp != null)
                    {
                        temp.recycle();
                        temp = null;
                    }
                }
            }

            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            synchronized (lock) {
                currentView = inflater.inflate(layoutIds.get(values[0]), null);
                // Notify async thread that inflate is done. 
                lock.notifyAll();
            }
        }

    }

編集済み

ここには 2 つのスレッドがあります。1 つはスレッド プールである AsyncTask で、もう 1 つは UI スレッドです。

同期ブロックを使用すると、別のスレッドをスリープまたは待機していない限り、1 つのスレッドだけがオブジェクト ロックを使用できるようにすることができます。

したがって、1 つのスレッドが同期内でブロックを実行している場合、そのオブジェクトの監視を開始し、そのオブジェクトの同期ブロックを持つ他のスレッドが実行されないようにします。つまり、別のスレッドは、アクティブなスレッドがスリープ状態になるか、同期ブロック内で実行が完了するまで待機する必要があります。

詳細については、これを参照してください

ここでは、同期ブロックを使用して、UI スレッドが完了するのを待ちました。

そのため、lock.wait() を実行すると、AsyncThread は別のスレッドが同じオブジェクトに対して通知を呼び出すまで待機します。そして、lock.notifyAll() が呼び出されると、待機中のすべてのスレッド (AsyncThread) が再開されます。

于 2013-05-13T13:45:22.923 に答える