现在的位置: 首页 > 综合 > 正文

android媒体框架之图库行为

2013年04月08日 ⁄ 综合 ⁄ 共 4280字 ⁄ 字号 评论关闭

建议用用在设备休眠的时候第三方视频播放器主动调用VideoView.suspend()方法

我们很多第三方播放器应用在休眠唤醒的时候处理的不是很棒,造成很多平台不能很好的兼容,最进在公司就处理过此类问题。

默认情况下,当我们点击power键的时候,我们客户端播放器会和服务端断开连接,此时服务端的Client会析构,当再次返回时会重新唤醒时服务端会重新创建服务端,读取上次保存的位置,开始播放或者待用户确认后开始播放,这样做会节约功耗,你不希望用户用你产品后本来可以撑一天的手机,现在只能用半天了吧~

废话少说,直接把图库的行为给大家看下:

 

SEP 1 .MovieActivity

 

    @Override
    public void onPause() {
        mPlayer.onPause();
        super.onPause();
    }

当点击power键的时候,会调用movieActitivy的onPause方法

 

SEP 2. MoviePlayer

 

    public void onPause() {
        mHasPaused = true;
        mHandler.removeCallbacksAndMessages(null);
        mVideoPosition = mVideoView.getCurrentPosition();
        mBookmarker.setBookmark(mUri, mVideoPosition, mVideoView.getDuration());
        mVideoView.suspend();
        mResumeableTime = System.currentTimeMillis() + RESUMEABLE_TIMEOUT;
    }

保存状态,保存为书签,调用VideoView的挂起方法,其真正调用的是VideoView的release方法

 

SEP 3 .ViewoView

 

    /*
     * release the media player in any state
     */
    private void release(boolean cleartargetstate) {
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
            if (cleartargetstate) {
                mTargetState  = STATE_IDLE;
            }
        }
    }

 

SEP4.MediaPlay.java

 

 public void release() {
        stayAwake(false);
        updateSurfaceScreenOn();
        mOnPreparedListener = null;
        mOnBufferingUpdateListener = null;
        mOnCompletionListener = null;
        mOnSeekCompleteListener = null;
        mOnErrorListener = null;
        mOnInfoListener = null;
        mOnVideoSizeChangedListener = null;
        mOnTimedTextListener = null;
        _release();
    }

    private native void _release();


...  ...


public void reset() {
        stayAwake(false);
        _reset();
        // make sure none of the listeners get called anymore
        mEventHandler.removeCallbacksAndMessages(null);
    }

    private native void _reset();

先说reset:

 

SEP5.android_media_MediaPlayer.cpp

 

// If exception is NULL and opStatus is not OK, this method sends an error
// event to the client application; otherwise, if exception is not NULL and
// opStatus is not OK, this method throws the given exception to the client
// application.
static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
{
    if (exception == NULL) {  // Don't throw exception. Instead, send an event.
        if (opStatus != (status_t) OK) {
            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
            if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
        }
    } else {  // Throw exception!
        if ( opStatus == (status_t) INVALID_OPERATION ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
        } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
            jniThrowException(env, "java/lang/SecurityException", NULL);
        } else if ( opStatus != (status_t) OK ) {
            if (strlen(message) > 230) {
               // if the message is too long, don't bother displaying the status code
               jniThrowException( env, exception, message);
            } else {
               char msg[256];
                // append the status code to the message
               sprintf(msg, "%s: status=0x%X", message, opStatus);
               jniThrowException( env, exception, msg);
            }
        }
    }
}

 

SEP6.MediaPlayer.cpp

void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
... ...
// Allows calls from JNI in idle state to notify errors
    if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
        ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
        if (locked) mLock.unlock();   // release the lock when done.
        return;
    }
... ...
}

 

再回头看,release

 

SEP7.android_media_MediaPlayer.cpp

 

static void
android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
{
    ALOGV("release");
    decVideoSurfaceRef(env, thiz);
    sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
    if (mp != NULL) {
        // this prevents native callbacks after the object is released
        mp->setListener(0);
        mp->disconnect();
    }
}

SEP8.MediaPlayer.cpp

 

void MediaPlayer::disconnect()
{
    ALOGV("disconnect");
    sp<IMediaPlayer> p;
    {
        Mutex::Autolock _l(mLock);
        p = mPlayer;
        mPlayer.clear();
    }

    if (p != 0) {
        p->disconnect();
    }
}

这里的IMediaPlayer的指针指向的就是MdiaPlayerService::Client;智能指针clear就会调用其析构函数,然后断开与服务端的连接

 

SEP9.MediaPlayerService.cpp

MediaPlayerService::Client::~Client()
{
    ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
    mAudioOutput.clear();
    wp<Client> client(this);
    disconnect();
    mService->removeClient(client);
}

void MediaPlayerService::Client::disconnect()
{
    ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
    // grab local reference and clear main reference to prevent future
    // access to object
    sp<MediaPlayerBase> p;
    {
        Mutex::Autolock l(mLock);
        p = mPlayer;
    }
    mClient.clear();

    mPlayer.clear();

    // clear the notification to prevent callbacks to dead client
    // and reset the player. We assume the player will serialize
    // access to itself if necessary.
    if (p != 0) {
        p->setNotifyCallback(0, 0);
#if CALLBACK_ANTAGONIZER
        ALOGD("kill Antagonizer");
        mAntagonizer->kill();
#endif
        p->reset();
    }

    disconnectNativeWindow();

    IPCThreadState::self()->flushCommands();
}

关闭和服务端的连接流程基本就是这样的。返回流程后续补上。

 

 

 

 

 

 

 

 

 

 

 

 

抱歉!评论已关闭.