当前位置: 首页 > news >正文

360全景网站建设网站设计制作在哪里找

360全景网站建设,网站设计制作在哪里找,wordpress主题 中文,应用软件英文上一节了解了MediaPlayer api的使用,这一节就我们将会了解MediaPlayer的生命周期与api使用细节。 1、MediaPlayer生命周期 MediaPlayer.java 一开始有对生命周期的描述,这里对这些内容进行翻译: MediaPlayer 是线程不安全的,创建…

上一节了解了MediaPlayer api的使用,这一节就我们将会了解MediaPlayer的生命周期与api使用细节。

1、MediaPlayer生命周期

MediaPlayer.java 一开始有对生命周期的描述,这里对这些内容进行翻译:

  1. MediaPlayer 是线程不安全的,创建以及调用应该在同一个线程中,如果需要使用Callback,那么线程必须要有一个Looper;
  2. 调用 new 或者 reset 后MediaPlayer进入 Idle 状态,release 调用后进入到 End 状态,这两个状态之间就是 MediaPlayer 对象的生命周期;
  3. 调用 new 或者 reset都会进入Idle 状态,但是它们仍然是有区别的。getDuration 等方法在Idle 状态下调用会出现error,如果是new之后调用,虽然会返回error,但是error并不是由内部播放器引擎上抛的,播放器状态仍然保持在Idle 状态;如果刚好是在reset之后调用getDuration方法,那么内部播放器引擎会上抛error事件,并且把播放器状态置为Error
  4. 如果MediaPlayer对象不再需要被使用,推荐调用release方法,让内部播放器引擎使用的资源能够被释放;一旦进入了 End 状态,MediaPlayer对象将不能再被使用,并且不能再被切换到其他状态,如果仍要使用需要重新new一个对象,进入Idle状态。
  5. 有很多原因会造成播放失败,比如不支持的audio/video格式、分辨率过高、streaming超时等,这些错误会让播放器进入Error状态并且上抛事件,如果要继续使用当前MediaPlayer对象,可以调用reset使其进入到Idle状态;
  6. setDataSource会让播放器从Idle进入Loaded状态,如果在其他状态调用则会抛出IllegalStateException错误;
  7. prepare会让播放器从Loaded状态进入到Prepared状态,如果调用的是prepareAsync,则会先进入中间状态Preparing;在除了LoadedStopped状态外调用prepare方法都是非法的,会抛出IllegalStateException错误;
  8. start方法会让播放器从Prepared状态进入到Started状态,可以用isPlaying判断播放器当前状态是否在Started状态;如果已经进入到Started状态,则再调用start不会有任何影响;
  9. pause方法会让播放器进入到Paused状态,从Started进入到Paused或者反过来的过程都是异步的;如果已经进入到Paused状态,则再调用pause不会有任何影响;在Paused状态下重新调用start将会恢复播放,进入到Started状态;
  10. stop会让播放器从StartedPausedPreparedPlaybackCompleted状态进入到Stopped状态,一旦进入到Stopped状态,那么必须要调用prepare重新进入Prepared状态才能够重新进行播放;同样的,如果已经进入到Stopped状态,则再调用stop不会有任何影响;
  11. seekTo方法是异步的,调用完成后会有callback事件onSeekComplete上抛,seekTo可以在StartedPausedPreparedPlaybackCompleted状态下调用;
  12. 当播放结束时,如果setLooping设置为true,那么播放器将会保持在Started状态,如果setLooping设置为false,那么播放器将会进入到PlaybackCompleted状态;在PlaybackCompleted状态下,调用start方法将会从头开始重新播放,并且进入到Started状态。

2、异常处理

从上面我们可以了解到,MediaPlayer维护了一套状态机,并且调用MediaPlayer方法时会检查当前调用是否是非法的,这套状态机机制在 mediaplayer.cpp 中。 MediaPlayer 定义了如下状态:

enum media_player_states {MEDIA_PLAYER_STATE_ERROR        = 0,MEDIA_PLAYER_IDLE               = 1 << 0,MEDIA_PLAYER_INITIALIZED        = 1 << 1,MEDIA_PLAYER_PREPARING          = 1 << 2,MEDIA_PLAYER_PREPARED           = 1 << 3,MEDIA_PLAYER_STARTED            = 1 << 4,MEDIA_PLAYER_PAUSED             = 1 << 5,MEDIA_PLAYER_STOPPED            = 1 << 6,MEDIA_PLAYER_PLAYBACK_COMPLETE  = 1 << 7
};

要注意的是,End状态表示native MediaPlayer对象已经销毁了,所以它并没有真正的 End 状态。

MediaPlayer.java 中还有一段关于函数在什么状态下调用是有效的,什么状态下调用是无效的的表格,这里挑出一些进行翻译。

序号方法有效状态无效状态下调用
1getAudioSessionIdany
2getCurrentPositionInitialized, Prepared, Started, Paused, Stopped, PlaybackCompletedError
3getDurationPrepared, Started, Paused, Stopped, PlaybackCompletedError
4getVideoHeightany
5isPlayingany
6pauseStarted, Paused, PlaybackCompletedError
7prepareInitialized, Stopped异常
8prepareAsyncInitialized, Stopped异常
9releaseany
10resetany
11seekToPrepared, Started, Paused, PlaybackCompletedError
12setDataSourceIdle异常
13setDisplayany
15setSurfaceany
16setVideoScalingModeInitialized, Prepared, Started, Paused, Stopped, PlaybackCompleted
17setLoopingIdle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted
18startPrepared, Started, Paused, PlaybackCompletedError
19stopPrepared, Started, Stopped, Paused, PlaybackCompletedError

从以上表格我们可以发现,非法状态下调用prepareprepareAsyncsetDataSource会抛异常中止程序运行;调用startpause等方法会将状态置为 Error,具体程序如何反应需要看我们的OnErrorListener是如何处理的:

    case MEDIA_ERROR:Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");boolean error_was_handled = false;OnErrorListener onErrorListener = mOnErrorListener;if (onErrorListener != null) {error_was_handled = onErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);}{mOnCompletionInternalListener.onCompletion(mMediaPlayer);OnCompletionListener onCompletionListener = mOnCompletionListener;if (onCompletionListener != null && ! error_was_handled) {onCompletionListener.onCompletion(mMediaPlayer);}}stayAwake(false);return;

3、对new、release、reset的一些理解

相关代码路径:

  • MediaPlayer.java
  • android_media_MediaPlayer.cpp
  • mediaplayer.cpp

3.1、new

在看正式的 new MediaPlayer 流程前,我们先要注意MediaPlayer.java中的如下代码段:

    static {System.loadLibrary("media_jni");native_init();}

它会加载media_jni.so,并执行native函数 android_media_MediaPlayer_native_init 。native_init会获取java类中的postEventFromNative方法ID,mNativeContextmNativeSurfaceTexture等字段的ID,获取到的ID会存储在静态变量fields_t中,后期可以通过这些ID找到Java对象中对应的成员,获取其存储的值或者向其中存储值。

static fields_t fields;fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");

接下来看new MediaPlayer创建一个对象会做哪些事情:

private MediaPlayer(int sessionId) {...try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {native_setup(new WeakReference<MediaPlayer>(this), attributionSourceState.getParcel());}
}

核心是调用native_setup方法,需要将自身的弱引用对象作为参数向下传递:

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,jobject jAttributionSource)
{Parcel* parcel = parcelForJavaObject(env, jAttributionSource);android::content::AttributionSourceState attributionSource;attributionSource.readFromParcel(parcel);// 创建MediaPlayer native对象sp<MediaPlayer> mp = sp<MediaPlayer>::make(attributionSource);// 创建并注册Callback对象sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);mp->setListener(listener);// 将MediaPlayer对象存储到Java对象中setMediaPlayer(env, thiz, mp);
}

native_setup干了3件事:

  1. 创建MediaPlayer native对象;
  2. 用传下来的弱引用对象创建Listener对象,用于Callback调用;
  3. 将MediaPlayer native对象指针到Java对象中;

来看看如何存储MediaPlayer native指针的:

static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{Mutex::Autolock l(sLock);sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);// 手动增加强引用计数if (player.get()) {player->incStrong((void*)setMediaPlayer);}// 检查mNativeContext中存储的MediaPlayer对象if (old != 0) {old->decStrong((void*)setMediaPlayer);}// 将MediaPlayer的地址存储到mNativeContextenv->SetLongField(thiz, fields.context, (jlong)player.get());return old;
}

这里有3个步骤:

  1. 首先要增加MediaPlayer native对象的强引用计数;
  2. 检查mNativeContext中存储的地址是否为NULL,如果不为NULL则需要销毁存储的MediaPlayer对象;
  3. 将新的MediaPlayer对象存储到mNativeContext中。

虽然我们会把MediaPlayer对象存储到Java字段中,但是其引用计数在setMediaPlayer中仍为1,如不增加引用计数,出了当前作用域native对象将自动销毁。

3.2、reset

reset的作用是重置当前MediaPlayer对象,使其恢复到new的状态。我们来看下reset实现:

status_t MediaPlayer::reset_l()
{mLoop = false;if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;// 1.阻止 MEDIA_PREPARED 事件上抛mPrepareSync = false;if (mPlayer != 0) {// 2.调用内部实现的resetstatus_t ret = mPlayer->reset();if (ret != NO_ERROR) {ALOGE("reset() failed with return code (%d)", ret);mCurrentState = MEDIA_PLAYER_STATE_ERROR;} else {// 2.调用内部实现的disconnectmPlayer->disconnect();mCurrentState = MEDIA_PLAYER_IDLE;}// 3.销毁内部实现mPlayer = 0;return ret;}// 4.清除设置clear_l();return NO_ERROR;
}

reset主要会做3件事情:

  • 如果当前状态是Preparing,那么会将 mPrepareSync 置为fasle,阻止 MEDIA_PREPARED 事件上抛,具体内部如何操作后续再研究;
  • 调用 MediaPlayer 内部实例的 disconnect 方法断开连接,如果处在播放状态将会停止播放(这点后续再研究);
  • 销毁 MediaPlayer 内部实例;

3.3、release

release会直接销毁掉MediaPlayer native对象,一旦调用release,当前MediaPlayer java对象将不能够再被使用:

MediaPlayer::~MediaPlayer()
{ALOGV("destructor");if (mAudioAttributesParcel != NULL) {delete mAudioAttributesParcel;mAudioAttributesParcel = NULL;}AudioSystem::releaseAudioSessionId(mAudioSessionId, (pid_t)-1);disconnect();IPCThreadState::self()->flushCommands();
}

MediaPlayer 的析构函数同样也会调用内部实例的 disconnect 方法断开连接,之后会销毁 MediaPlayer 内部实例,这两点和reset是相同的。我们在想要结束activity,可以先调用reset,再调用release,也可以直接调用release来释放资源。

http://www.hkea.cn/news/224702/

相关文章:

  • 温州快建网站地推拉新接单网
  • 濉溪县城乡建设委员会燃气办网站热狗网站排名优化外包
  • 网站能不能自己做免费的seo教程
  • 湖南的商城网站建设优化教程网下载
  • 做网站需要哪些工程师西安seo诊断
  • tp做的网站封装成app2023北京封控了
  • 增城做网站要多少钱推广普通话手抄报
  • 石家庄网站系统开发智能搜索引擎
  • 迅速网站网络营销平台推广方案
  • 学前端要逛那些网站微信引流主动被加软件
  • 韩国flash网站免费手机网站建站平台
  • 东莞做网站卓诚网络昆明长尾词seo怎么优化
  • WordPress个性萌化插件郑州seo优化哪家好
  • 专业手机移动网站建设免费的seo优化
  • 西安网站建设王永杰域名注册 万网
  • 网站营销优化方案北京做的好的seo公司
  • 企业网站排名提升软件优化南宁seo优化
  • 创意合肥网站建设杭州seo公司排名
  • 网站专题页是什么中国十大关键词
  • 五月天做网站网络策划与营销
  • 高校网站如何建设论文谷歌官网下载
  • 做网站内容软件个人网站怎么做
  • 收废铁的做网站有优点吗海南百度推广开户
  • wordpress 二维码插件下载信阳搜索引擎优化
  • 个人网站二级域名做淘宝客企业推广策略
  • 厦门做网站seo的seo服务公司招聘
  • 安徽池州做企业网站百度搜索官方网站
  • 芜湖商城网站建设青岛百度快速优化排名
  • 我找伟宏篷布我做的事ko家的网站seoul怎么读
  • 即墨做网站优书网首页