Android:如何在无限循环中正确管理顺序线程

发布于 2024-12-08 22:16:37 字数 4833 浏览 1 评论 0原文

我在 onHandleIntent 内创建了带有无限循环的 IntentService ,然后添加静态方法 start、resume、pause、stop 以在我的 Activity 中直接调用它。

场景是,在无限循环内,我调用回调方法,该方法创建一个新线程来执行长进程。

问题是,我担心由于无限循环而不断创建线程。我很确定有更好的方法来管理它。我正在考虑 ThreadPool 或某种能够以顺序方式仅使用一个线程的东西。这样,我就节省了时间、内存、开销等。

非常欢迎其他方法。根据需要询问我其他信息。那么,我就在这里更新一下。

这是我的代码(看看 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 除了 google api 之外,我还使用 location api。我将创建一个 android 库项目并使用该 api 在后台获取最新位置(例如每 2 秒)。

在应用程序端,只需要调用静态方法即可使用它(例如start(context,callback),pause(),resume(),stop())。它有回调来获取位置。从位置对象获取所需信息后,我将创建一个新线程来调用我自己创建的回调(由应用程序端实现)。

I have created IntentService with infinite loop inside the onHandleIntent then add static methods start,resume,pause,stop to directly call it within my Activities.

The scenario is, inside the infinite loop, I am calling callback methods which is creating a new thread to execute long process.

The problem is, I am worrying about continuously creating Threads due to infinite loop. I am pretty sure that there is better way to manage it. I am thinking of ThreadPool or something enable to use only one thread in a sequential manner. So that, I am saving time,memory,overheads etc..

OTHER APPROACH ARE VERY WELCOME. Ask me other information as needed. Then, I will update here.

Here are my codes(take a look at 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
I am using location api aside from google api. I will create a android library project and use that api to get the latest location (e.g. every 2secs) in the background.

On the application side, just need to call static methods to use it (e.g. start(context, callback), pause(), resume(), stop()). It has callbacks to obtain the location. After obtaining the needed information from the location object, I will create a new thread to call my own created callbacks (which implemented by the application side).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

画骨成沙 2024-12-15 22:16:37

您可以使用 AsyncTask 而不是创建每次都有新线程? AsyncTask 管理固定的线程池(或一个后台线程 - 取决于 Android 版本),并允许执行后台操作并在 UI 线程上发布结果,而无需操作线程和/或处理程序。

但是我想知道为什么需要在 onHandleIntent 方法内创建无限循环?通过这样做,您可以防止您的 IntentService接收进一步的意向。由于在 IntentService 中:

所有请求都在单个工作线程上处理——它们可能会被视为
根据需要(并且不会阻塞应用程序的主循环),
但一次只会处理一个请求。

我认为您想要在 IntentService 中的 UI 线程之外执行一些长时间运行的代码。但这不需要在 IntentService 工作线程中创建无限循环。只需使用 Context.startService(Intent) 调用。如果您希望 IntentService 发送回一些结果或只是在 UI 线程中调用回调,您可以传递 Messenger (或 < code>ResultReceiver) 对象意图。

活动

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

IntentService

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

You can use AsyncTask instead of creating a new thread every time? AsyncTask manages a fixed pool of threads (or one background thread - depending on Android version) and allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

However I wonder why do you need to create an infinite loop inside the onHandleIntent method? By doing that you prevent your IntentService from receiving further Intents. Since in IntentService:

All requests are handled on a single worker thread -- they may take as
long as necessary (and will not block the application's main loop),
but only one request will be processed at a time.

I think you want to execute some long-running code out of the UI thread in the IntentService. But that doesn't require the creation of an infinite loop in the IntentService worker thread. Just send the requests as needed to the IntentService using Context.startService(Intent) call. If you want IntentService to send back some result or just call a callback in the UI thread you can pass a Messenger (or a ResultReceiver) object with the Intent.

Activity:

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

IntentService:

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()); 
}
如梦 2024-12-15 22:16:37

查看 ExecutorService 的文档(不要与 Android 混淆) Services)和 Executors 包。这里有一些关于如何使用线程池的示例。

Look into the docs for ExecutorService (not to be confused with Android Services) and the Executors package. There are a few examples there on how to use thread pools.

泪意 2024-12-15 22:16:37

等等,为什么需要使用所有这些回调?难道你不能让每个意图编码需要完成的事情,然后让你的 onHandleIntent 根据意图的信息执行不同的代码吗?这就是 IntentService 的使用方式。

您不应该在 IntentSerivce 中执行任何线程处理。 IntentService 应该处理所有线程代码(并且您应该允许它,因为它可能是高度优化的)。

So wait, why do you need to use all these callbacks? Can't you just have each intent encode what needs to be done and then have your onHandleIntent execute different code based on the information of the intent. This is the way IntentService is intended to be used.

You shouldn't be doing any of the thread handling in the IntentSerivce. The IntentService is supposed to be handling all the threading code (and you should let it because it's probably highly optimized).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文