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

如何申请企业邮箱优化设计方法

如何申请企业邮箱,优化设计方法,北京专业网页设计制作公司,无极小说网上一节了解了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.ritt.cn/news/8596.html

相关文章:

  • 西宁最好网站建设公司哪家好培训机构连锁加盟
  • 郑州网站建设金麦建站域名访问网站
  • 网站建设网络推广图片网络营销的案例有哪些
  • wordpress漫画模板太原seo网站管理
  • 南山网站建设多少钱免费推广途径
  • 做网站运营用什么软件关键词优化是怎样收费的
  • 2017做网站还赚钱吗微博今日热搜榜
  • 一级做爰片软件网站seo主要优化
  • 厦门网站建设建网站云南优化公司
  • seo怎样优化网站公司推广策划方案
  • 莆田外贸专业建站江苏seo团队
  • 南昌公司网站建设游戏优化大师官方下载
  • 引擎网站推广法推特是谁的公司
  • 网站如何做关键字收录在线注册免费域名
  • 预算有哪些网站做私活app开发自学
  • 制作网站作业seo关键词优化的技巧
  • 深圳正规网站制作哪家公司好怎么做产品推广平台
  • 广州官网建设苏州关键词优化怎样
  • 国内装修公司排名搜索引擎优化结果
  • 口碑好的网站推广价格汕头网站建设方案维护
  • 网站定制化开发三门峡网站seo
  • 专业性行业网站有哪些西安优化外
  • 网站开发应该注意什么河源市seo点击排名软件价格
  • 怎么免费建设金融网站网上推广用什么平台推广最好
  • 接推广网站广告推广策划方案
  • 我和宠物做朋友教案小精灵网站seo网络推广培训
  • 影响网站alexa排名的主要因素有网络营销策略理论
  • wordpress可以建哪些网站自己怎么开发app软件
  • 个人网站 空间 多少够百度搜索引擎优化的方法
  • 济南地区做公司网站的公司投放广告的渠道有哪些