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

时间:2015-03-01 19:09:51

标签: java android multithreading concurrency callback

我仍然是java和Android的新手,我正在使用Android示例代码MediaBrowserService。

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

我对此线程的限制有疑问。 例如,以下是在公共类MusicProvider中声明的:

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

在同一个类中使用以下引用:

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

然后在公共类MusicService(扩展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窗口中使用以下输出运行应用程序:

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环境中处理它。 / p>

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

1 个答案:

答案 0 :(得分:3)

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

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

  • doInBackground()的{​​{1}}和onPostExecute()方法。
  • 排球的AsyncTaskonResponse()方法onError()

但是,这些都不是您描述的类型的真正接口回调。这些是在派生类中重写的虚方法。我必须承认,到目前为止,我已经从未看到在Android应用开发中两个线程之间同步的接口回调。