在 Android 中同步不同线程之间的回调

Synchronizing callbacks between different threads in Android

我对 java 和 Android 还是比较陌生,正在使用 Android 示例代码 MediaBrowserService。

我利用该代码了解 MediaController 和 MediaSession 如何协同工作。回调用于该使用模式。我在该示例中还看到,用户定义的 classes 也使用回调范例。

我对线程限制有疑问。 例如,在 public class MusicProvider 中声明如下:

public interface Callback {
void onMusicCatalogReady(boolean success);
}

与以下引用相同class:

private void retrieveMediaAsync(Callback callback) {
    initializationLock.lock();
        //...
        //code removed
        //...
        if (callback != null) {
            Log.w(" CB_REF1",":");

            callback.onMusicCatalogReady(mCurrentState == State.INITIALIZED);
        }
    }
}

和:

public void retrieveMedia(final Callback callback) {
        //...
        //code removed
        //...
        Log.w(" CB_REF2",":");
        callback.onMusicCatalogReady(true);
        return;
    }

然后在publicclassMusicService(扩展MediaBrowserService)中有如下定义:

public void onCreate() {
    //...
    //code removed
    //...
    super.onCreate();
    Log.w(" CB_DEF2",":");
    mMusicProvider.retrieveMedia(new MusicProvider.Callback() {
        @Override
        public void onMusicCatalogReady(boolean success) {

            mState = success ? PlaybackState.STATE_NONE : PlaybackState.STATE_ERROR;
        }
    });

和:

public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
        //...
        //code removed
        //...

        Log.w(" CB_DEF1",":");
        mMusicProvider.retrieveMedia(new MusicProvider.Callback() {
            @Override
            public void onMusicCatalogReady(boolean success) {

                if (success) {
                    loadChildrenImpl(parentMediaId, result);
                } else {
                    updatePlaybackState(getString(R.string.error_no_metadata));
                    result.sendResult(new ArrayList<MediaItem>());
                }
            }
        });

然后我 运行 应用程序在 Logcat window 中具有以下输出:

03-01 12:19:32.607    1929-1929/com.example.android.mediabrowserservice W/CB_DEF2﹕ :
03-01 12:19:32.794    1929-1929/com.example.android.mediabrowserservice W/CB_DEF2﹕ :
03-01 12:19:32.957    1929-1929/com.example.android.mediabrowserservice W/CB_DEF1﹕ :
03-01 12:19:33.294    1929-2053/com.example.android.mediabrowserservice W/CB_REF1﹕ :
03-01 12:19:45.329    1929-1929/com.example.android.mediabrowserservice W/CB_DEF2﹕ :
03-01 12:19:45.347    1929-1929/com.example.android.mediabrowserservice W/CB_DEF1﹕ :
03-01 12:19:45.426    1929-2033/com.example.android.mediabrowserservice W/CB_REF1﹕ :
03-01 12:19:45.428    1929-2033/com.example.android.mediabrowserservice W/CB_REF1﹕ :
03-01 12:19:47.622    1929-1929/com.example.android.mediabrowserservice W/CB_DEF2﹕ :
03-01 12:19:47.643    1929-1929/com.example.android.mediabrowserservice W/CB_DEF1﹕ :
03-01 12:19:47.732    1929-2053/com.example.android.mediabrowserservice W/CB_REF1﹕ :
03-01 12:19:47.734    1929-2033/com.example.android.mediabrowserservice W/CB_REF1﹕ :

所以我可以看到(并且有点理解)如何通过将特定定义注册为回调来根据需要重新定义回调函数。

我的问题与多线程相关的行为有关。

注册不同回调方法的能力是否意味着所有这些注册都必须发生在与回调调用相同的线程中,以确保调用回调时回调注册不处于某个中间状态?

如果不是这种情况,那么在我看来,当回调被调用时,注册回调的指令可能处于某种中间状态,我不确定如何在 Android环境。

感谢您考虑我的问题。 吉姆

Android遵循单线程模型,也就是说所有UI相关的操作只发生在主线程,所有非UI的操作都需要明确在单独的线程上执行。因此,回调的线程同步并不是大多数人谈论的话题。如果我们在两个不同线程上的操作之间发送回调,那么 有必要这样做。框架设计者之所以采用单线程策略,正是因为因为线程同步对大多数程序员来说是一个棘手的问题。

您确实提出了一个有趣的问题,作为回答,以这种方式(由框架)同步的回调示例是:

  • AsyncTaskdoInBackground()onPostExecute() 方法。
  • 齐射的 onResponse()onError() 方法 Request

但是,其中 none 是您所描述类型的真实接口回调。这些是在派生 class 中覆盖的虚拟方法。我不得不承认,到目前为止,我从未看到接口回调在Android应用程序开发中的两个线程之间同步。