2

IntentService内部に無限ループを作成しonHandleIntent、静的メソッドstart、resume、pause、stopを追加して、アクティビティ内で直接呼び出します。

シナリオは、無限ループ内で、長いプロセスを実行するための新しいスレッドを作成するコールバックメソッドを呼び出しています。

問題は、無限ループが原因でスレッドが継続的に作成されることを心配していることです。私はそれを管理するためのより良い方法があるとかなり確信しています。ThreadPoolか、1つのスレッドだけを順番に使用できるものを考えています。そのため、時間、メモリ、オーバーヘッドなどを節約できます。

他のアプローチは大歓迎です。必要に応じて他の情報を聞いてください。次に、ここで更新します。

これが私のコードです(SampleCallbackを見てください):

IntentService

import android.app.IntentService;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class SampleCallbackIntentService extends IntentService {
    private final String LOG_LOGCAT_TAG = "SampleCallbackIntentService";
    private Handler _handler;

    public SampleCallbackIntentService(String name) {
        super(name);
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // initialize variables for pause & resume thread
        _mPauseLock = new Object();
        _mPaused = false;
        _mFinished = false;

        // initialize handler to switch to UI/Main thread
         _handler = new Handler()
            {
                @Override
                public void handleMessage(final Message msg)
                {
                    _callback.doSomethingFromUIThread(msg);
                }
            };
    }

    private final SampleCallback _callback = new SampleCallback() {
        @Override
        public void doSomethingFromCurrentThread(final Object object) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //do long running process.
                                    // I will access object here.
                }
            }).start();

        }

        @Override
        public void doSomethingFromUIThread(final Message msg) {
            //may update UI here.
        }
    };

    private final int CALLBACK_MESSAGE = 1;
    @Override
    protected void onHandleIntent(Intent arg0) {
        Log.i(LOG_LOGCAT_TAG, "loop started");
        while (!_mFinished) {
            // do stuff here
            // create the object variable. Then pass to callback method
            _callback.doSomethingFromCurrentThread(object);

            // process and create the result to pass
            String someResult = "some result here";
            _handler.sendMessage(_handler.obtainMessage(CALLBACK_MESSAGE, someResult));

            synchronized (_mPauseLock) {
                while (_mPaused) {
                    try {
                        Log.i(LOG_LOGCAT_TAG, "loop paused");
                        _mPauseLock.wait();
                        Log.i(LOG_LOGCAT_TAG, "loop resumed");
                    } catch (InterruptedException e) {
                        Log.e(LOG_LOGCAT_TAG, "error occured on pause", e);
                    }
                }
            }
            try {
                //using sleep here might be not good design.
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Log.e(LOG_LOGCAT_TAG, "error occured on sleep", e);
            }
        }
        Log.i(LOG_LOGCAT_TAG, "loop ended");
    }

    private static Object _mPauseLock;
    private static boolean _mPaused;
    private static boolean _mFinished;

     public static void start(Context context) {
         Intent service = new Intent(context, SampleCallbackIntentService .class);
         if(context.startService(service)==null) {
             Log.e(LOG_LOGCAT_TAG, "Service cannot be started");
         } else {
             Log.i(LOG_LOGCAT_TAG, "start() called");
         }

     }

    /**
     * Call this on pause.
     */
    public static void pause() {
        Log.i(LOG_LOGCAT_TAG, "pause() called");
        synchronized (_mPauseLock) {
            _mPaused = true;
        }
    }

    /**
     * Call this on resume.
     */
    public static void resume() {
        Log.i(LOG_LOGCAT_TAG, "resume() called");
        synchronized (_mPauseLock) {
            _mPaused = false;
            _mPauseLock.notifyAll();
        }
    }

     public static void stop() {
         if(_mPauseLock == null) return;
         synchronized (_mPauseLock) {
             Log.i(LOG_LOGCAT_TAG, "stop() called");
             _mFinished = true;
         }
     }
}

SampleCallback

import android.os.Message;

public interface SampleCallback {

    public void doSomethingFromCurrentThread(final Object object);

    public void doSomethingFromUIThread(final Message msg);
}

UPDATES1 私はグーグルAPIとは別にロケーションAPIを使用しています。Androidライブラリプロジェクトを作成し、そのAPIを使用して、バックグラウンドで最新の場所(2秒ごとなど)を取得します。

アプリケーション側では、静的メソッドを呼び出して使用する必要があります(たとえば、start(context、callback)、pause()、resume()、stop())。場所を取得するためのコールバックがあります。ロケーションオブジェクトから必要な情報を取得した後、自分で作成したコールバック(アプリケーション側で実装)を呼び出すための新しいスレッドを作成します。

4

3 に答える 3

2

AsyncTask毎回新しいスレッドを作成する代わりに使用できますか? AsyncTask は、スレッドの固定プール (または 1 つのバックグラウンド スレッド - Android のバージョンによって異なります) を管理し、スレッドやハンドラーを操作することなく、バックグラウンド操作を実行し、UI スレッドで結果を発行できるようにします。

onHandleIntentしかし、メソッド内で無限ループを作成する必要があるのはなぜでしょうか? そうすることで、IntentServiceそれ以上のインテントを受け取ることができなくなります。IntentService以降:

すべてのリクエストは 1 つのワーカー スレッドで処理されます。必要なだけ時間がかかる場合がありますが (アプリケーションのメイン ループをブロックすることはありません)、一度に処理されるリクエストは 1 つだけです。

IntentService の UI スレッドから実行時間の長いコードを実行したいと思います。ただし、IntentService ワーカー スレッドで無限ループを作成する必要はありません。call を使用して、必要に応じてリクエストを IntentService に送信するだけContext.startService(Intent)です。IntentService に何らかの結果を送り返したり、UI スレッドでコールバックを呼び出したりする場合は、Messenger(またはResultReceiver) オブジェクトを Intent と共に渡すことができます。

アクティビティ:

final Handler uiHandler = new Handler(Looper.getMainLooper());

private void postTask() {
  Intent intent = new Intent("com.yourservice.DOACTION");
  intent.putExtra("messenger", new Messenger(handler));
  intent.putExtra("object", YourObject());   // pass other Parcelable objects
  startService(intent);
}

インテントサービス:

protected void onHandleIntent(Intent intent) {
  Messenger messenger = intent.getParcelableExtra("messenger");
  YourObject object = intent.getParcelableExtra("object");

  //... do work here ...

  Message msg = Message.obtain();
  msg.what = CALLBACK_MESSAGE;
  msg.setData(someResult);
  messenger.send(Message.obtain()); 
}
于 2011-10-14T11:29:12.393 に答える
1

ExecutorService(Androidサービスと混同しないでください)およびExecutorsパッケージのドキュメントを調べてください。スレッドプールの使用方法に関する例がいくつかあります。

于 2011-10-06T02:42:16.593 に答える
0

では、なぜこれらすべてのコールバックを使用する必要があるのでしょうか。各インテントに何をする必要があるかをエンコードしてから、インテントの情報に基づいて onHandleIntent に異なるコードを実行させることはできませんか。これが IntentService の使用方法です。

IntentSerivce でスレッド処理を行うべきではありません。IntentService は、すべてのスレッド化コードを処理することになっています (高度に最適化されている可能性があるため、許可する必要があります)。

于 2011-10-18T20:07:02.077 に答える