在之前的项目中用到了视频播放的功能,在网上看了看使用了大家用的比较多的一个开源项目JiaoZiVideo可以迅速的实现视频播放的相关功能。

JiaoZiVideo的简单使用

集成了JiaoZiVideo后仅需这几行代码就可以实现播放视频

JZVideoPlayerStandard jzVideoPlayerStandard = (JZVideoPlayerStandard) findViewById(R.id.jz_vedio);

//设置播放视频链接和视频标题

jzVideoPlayerStandard.setUp(VEDIO_URL

, JZVideoPlayer.SCREEN_WINDOW_NORMAL, "饺子在哪里");

//为播放视频设置封面图

jzVideoPlayerStandard.thumbImageView.setImageResource(R.mipmap.ic_launcher);

Jz播放器的简单使用,只需要在布局文件中引入该文件,然后为其设置待播放视频的链接和播放视频的封面图即可。其它的播放相关的无需我们关心。

代码结构分析

image.png

JiaoZiVideo主要特点

可以完全自定义UI和任何功能

可以完全自定义UI和任何功能

一行代码切换播放引擎,支持的视频格式和协议取决于播放引擎,android.media.MediaPlayer ijkplayer

完美检测列表滑动

可实现全屏播放,小窗播放

能在ListView、ViewPager和ListView、ViewPager和Fragment等多重嵌套模式下全屏工作

可以在加载、暂停、播放等各种状态中正常进入全屏和退出全屏

多种视频适配屏幕的方式,可铺满全屏,可以全屏剪裁

重力感应自动进入全屏

全屏后手势修改进度和音量

Home键退出界面暂停播放,返回界面继续播放

JiaoZiVideo的使用指南

1..添加类库

implementation 'cn.jzvd:jiaozivideoplayer:7.0.3'

2.添加布局

android:layout_width="match_parent"

android:layout_height="200dp">

android:id="@+id/jz_video"

android:layout_width="match_parent"

android:layout_height="200dp" />

3.设置视频地址、缩略图地址、标题

MyJzvdStd jzvdStd = (MyJzvdStd) findViewById(R.id.jz_video);

jzvdStd.setUp("http://jzvd.nathen.cn/c6e3dc12a1154626b3476d9bf3bd7266/6b56c5f0dc31428083757a45764763b0-5287d2089db37e62345123a1be272f8b.mp4"

, "饺子闭眼睛");

jzvdStd.thumbImageView.setImage("http://p.qpic.cn/videoyun/0/2449_43b6f696980311e59ed467f22794e792_1/640");

4.在Activity中

@Override

public void onBackPressed() {

if (Jzvd.backPress()) {

return;

}

super.onBackPressed();

}

@Override

protected void onPause() {

super.onPause();

Jzvd.releaseAllVideos();

}

5.在AndroidManifest.xml中

android:name=".MainActivity"

android:configChanges="orientation|screenSize|keyboardHidden"

android:screenOrientation="portrait" />

以上只是简单的播放视频功能,但是大家的项目需求里应该不仅仅只是需要播放视频就好了,所以下面写一下还有哪些常规使用方法

Glide.with(this).load(Url).into(myJzvdStd.thumbImageView); //推荐使用Glide

自动播放有两种 这里随便选择添加一个,

1. myJzvdStd.startButton.performClick();

2. myJzvdStd.startVideo();

//这里只有开始播放时才生效

mJzvdStd.seekToInAdvance = 20000;

//跳转制定位置播放

JZMediaManager.seekTo(30000);

2.播放sd卡下视频

public void cpAssertVideoToLocalPath() {

try {

InputStream myInput;

OutputStream myOutput = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/local_video.mp4");

myInput = this.getAssets().open("local_video.mp4");

byte[] buffer = new byte[1024];

int length = myInput.read(buffer);

while (length > 0) {

myOutput.write(buffer, 0, length);

length = myInput.read(buffer);

}

myOutput.flush();

myInput.close();

myOutput.close();

} catch (IOException e) {

e.printStackTrace();

}

}

myJzvdStd.setUp(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/local_video.mp4", "饺子不信",Jzvd.SCREEN_WINDOW_NORMAL, );

这里很多人问为什么播不了,请认真怒url,播不了就是url没怒对

复制Demo中CustomMediaPlayerAssertFolder类到你的项目下

----------------------------------------------------------------------------

JZDataSource jzDataSource = null;

try {

jzDataSource = new JZDataSource(getAssets().openFd("local_video.mp4"));

jzDataSource.title = "饺子快长大";

} catch (IOException e) {

e.printStackTrace();

}

jzvdStd.setUp(jzDataSource, JzvdStd.SCREEN_WINDOW_NORMAL);

Glide.with(this)

.load("http://jzvd-pic.nathen.cn/jzvd-pic/1bb2ebbe-140d-4e2e-abd2-9e7e564f71ac.png")

.into(jzvdStd.thumbImageView);

Jzvd.setMediaInterface(new CustomMediaPlayerAssertFolder());//进入此页面修改MediaInterface,让此页面的jzvd正常工作

JzvdStd.startFullscreen(this, JzvdStd.class, VideoConstant.videoUrlList[6], "饺子辛苦了");

mJzvdStd.startWindowTiny();

1.Listview

listView.setOnScrollListener(new AbsListView.OnScrollListener() {

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

Jzvd.onScrollAutoTiny(view, firstVisibleItem, visibleItemCount, totalItemCount);

// Jzvd.onScrollReleaseAllVideos(view, firstVisibleItem, visibleItemCount, totalItemCount); 这是不开启列表划出小窗 同时也是画出屏幕释放JZ 划出暂停

}

});

2. RecyclerView 划出列表开启小窗

recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {

@Override

public void onChildViewAttachedToWindow(View view) {

Jzvd.onChildViewAttachedToWindow(view, R.id.videoplayer);

}

@Override

public void onChildViewDetachedFromWindow(View view) {

Jzvd.onChildViewDetachedFromWindow(view);

}

});

2.1 RecyclerView划出屏幕释放JZ,同时也是不开启列表划出显示小窗

recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {

@Override

public void onChildViewAttachedToWindow(View view) {

}

@Override

public void onChildViewDetachedFromWindow(View view) {

Jzvd jzvd = view.findViewById(R.id.videoplayer);

if (jzvd != null && jzvd.jzDataSource.containsTheUrl(JZMediaManager.getCurrentUrl())) {

Jzvd currentJzvd = JzvdMgr.getCurrentJzvd();

if (currentJzvd != null && currentJzvd.currentScreen != Jzvd.SCREEN_WINDOW_FULLSCREEN) {

Jzvd.releaseAllVideos();

}

}

}

});

创建一个类继承JzvdStd并在XML设置

public class JzvdStdVolumeAfterFullscreen extends JzvdStd {

public JzvdStdVolumeAfterFullscreen(Context context) {

super(context);

}

public JzvdStdVolumeAfterFullscreen(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public void onPrepared() {

super.onPrepared();

if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {

JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f);

} else {

JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f);

}

}

/**

* 进入全屏模式的时候关闭静音模式

*/

@Override

public void startWindowFullscreen() {

super.startWindowFullscreen();

JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f);

}

/**

* 退出全屏模式的时候开启静音模式

*/

@Override

public void playOnThisJzvd() {

super.playOnThisJzvd();

JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f);

}

}

创建一个类继承JzvdStd并在XML设置

public class JzvdStdAutoCompleteAfterFullscreen extends JzvdStd {

public JzvdStdAutoCompleteAfterFullscreen(Context context) {

super(context);

}

public JzvdStdAutoCompleteAfterFullscreen(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public void startVideo() {

if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {

Log.d(TAG, "startVideo [" + this.hashCode() + "] ");

initTextureView();

addTextureView();

AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);

mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

JZUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

JZMediaManager.setDataSource(jzDataSource);

JZMediaManager.instance().positionInList = positionInList;

onStatePreparing();

} else {

super.startVideo();

}

}

@Override

public void onAutoCompletion() {

if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {

onStateAutoComplete();

} else {

super.onAutoCompletion();

}

}

}

复制DEMO下的layout文件在 layout_top 布局下 添加你的分享按钮

public class JzvdStdShowShareButtonAfterFullscreen extends JzvdStd {

public ImageView shareButton;

public JzvdStdShowShareButtonAfterFullscreen(Context context) {

super(context);

}

public JzvdStdShowShareButtonAfterFullscreen(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public void init(Context context) {

super.init(context);

shareButton = findViewById(R.id.share);

shareButton.setOnClickListener(this);

}

@Override

public int getLayoutId() {

return R.layout.layout_standard_with_share_button;

}

@Override

public void onClick(View v) {

super.onClick(v);

if (v.getId() == R.id.share) {

Toast.makeText(getContext(), "Whatever the icon means", Toast.LENGTH_SHORT).show();

}

}

@Override

public void setUp(JZDataSource jzDataSource, int screen) {

super.setUp(jzDataSource, screen);

if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {

shareButton.setVisibility(View.VISIBLE);

} else {

shareButton.setVisibility(View.INVISIBLE);

}

}

}

public class JzvdStdShowTitleAfterFullscreen extends JzvdStd {

public JzvdStdShowTitleAfterFullscreen(Context context) {

super(context);

}

public JzvdStdShowTitleAfterFullscreen(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public void setUp(JZDataSource jzDataSource, int screen) {

super.setUp(jzDataSource, screen);

if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {

titleTextView.setVisibility(View.VISIBLE);

} else {

titleTextView.setVisibility(View.INVISIBLE);

}

}

}

public class JzvdStdMp3 extends JzvdStd {

public JzvdStdMp3(Context context) {

super(context);

}

public JzvdStdMp3(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public int getLayoutId() {

return R.layout.jz_layout_standard_mp3;

}

@Override

public void onClick(View v) {

if (v.getId() == cn.jzvd.R.id.thumb &&

(currentState == CURRENT_STATE_PLAYING ||

currentState == CURRENT_STATE_PAUSE)) {

onClickUiToggle();

} else if (v.getId() == R.id.fullscreen) {

} else {

super.onClick(v);

}

}

//changeUiTo 真能能修改ui的方法

@Override

public void changeUiToNormal() {

super.changeUiToNormal();

}

@Override

public void changeUiToPreparing() {

super.changeUiToPreparing();

}

@Override

public void changeUiToPlayingShow() {

super.changeUiToPlayingShow();

thumbImageView.setVisibility(View.VISIBLE);

}

@Override

public void changeUiToPlayingClear() {

super.changeUiToPlayingClear();

thumbImageView.setVisibility(View.VISIBLE);

}

@Override

public void changeUiToPauseShow() {

super.changeUiToPauseShow();

thumbImageView.setVisibility(View.VISIBLE);

}

@Override

public void changeUiToPauseClear() {

super.changeUiToPauseClear();

thumbImageView.setVisibility(View.VISIBLE);

}

@Override

public void changeUiToComplete() {

super.changeUiToComplete();

}

@Override

public void changeUiToError() {

super.changeUiToError();

}

}

jzvdStdMp3 = findViewById(R.id.jz_videoplayer_mp3);

jzvdStdMp3.setUp(URL, "饺子摇摆", Jzvd.SCREEN_WINDOW_NORMAL);

Glide.with(this)

.load(VideoConstant.videoThumbs[0][1])

.into(jzvdStdMp3.thumbImageView);

public class JzvdStdShowTextureViewAfterAutoComplete extends JzvdStd {

public JzvdStdShowTextureViewAfterAutoComplete(Context context) {

super(context);

}

public JzvdStdShowTextureViewAfterAutoComplete(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public void onAutoCompletion() {

super.onAutoCompletion();

thumbImageView.setVisibility(View.GONE);

}

}

@Override

protected void onResume() {

super.onResume();

//home back

JzvdStd.goOnPlayOnResume();

}

@Override

protected void onPause() {

super.onPause();

// Jzvd.clearSavedProgress(this, null);

//home back

JzvdStd.goOnPlayOnPause();

}

1. 集成videocache implementation 'com.danikula:videocache:2.7.0',并初始化

public class ApplicationDemo extends Application {

@Override

public void onCreate() {

super.onCreate();

// LeakCanary.install(this);

}

private HttpProxyCacheServer proxy;

public static HttpProxyCacheServer getProxy(Context context) {

ApplicationDemo app = (ApplicationDemo) context.getApplicationContext();

return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;

}

private HttpProxyCacheServer newProxy() {

return new HttpProxyCacheServer(this);

}

}

2.引用

LinkedHashMap map = new LinkedHashMap();

String proxyUrl = ApplicationDemo.getProxy(this).getProxyUrl(VideoConstant.videoUrls[0][9]);

map.put("高清", proxyUrl);

map.put("标清", VideoConstant.videoUrls[0][6]);

map.put("普清", VideoConstant.videoUrlList[0]);

JZDataSource jzDataSource = new JZDataSource(map, "饺子不信");

jzDataSource.looping = true;

jzDataSource.currentUrlIndex = 2;

jzDataSource.headerMap.put("key", "value");//header

mJzvdStd.setUp(jzDataSource

, JzvdStd.SCREEN_WINDOW_NORMAL);

Glide.with(this).load(VideoConstant.videoThumbList[0]).into(mJzvdStd.thumbImageView);

创建一个类集成JzvdStd并在XML设置

public class JZVideoPlayerStandardLoopVideo extends JzvdStd{

public JZVideoPlayerStandardLoopVideo (Context context) {

super(context);

}

public JZVideoPlayerStandardLoopVideo (Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public void onAutoCompletion() {

super.onAutoCompletion();

startVideo();

}

}

还有一种方法就是上面清晰度切换loop循环标志

SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

Jzvd.JZAutoFullscreenListener mSensorEventListener = new Jzvd.JZAutoFullscreenListener();

@Override

protected void onResume() {

super.onResume();

Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

mSensorManager.registerListener(mSensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);

}

@Override

protected void onPause() {

super.onPause();

mSensorManager.unregisterListener(mSensorEventListener);

}

Jzvd.FULLSCREEN_ORIENTATION=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;

Jzvd.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;

两个变量控制全屏前后的屏幕方向

Jzvd.SAVE_PROGRESS = false;

Jzvd.WIFI_TIP_DIALOG_SHOWED=true;

Jzvd.clearSavedProgress(this, "url");

ijk

复制Demo中JZMediaIjkplayer类到你的项目下

implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'

implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'

Jzvd.setMediaInterface(new JZMediaIjkplayer()); // ijkMediaPlayer

Mediaplayer

Jzvd.setMediaInterface(new JZMediaSystem()); //

exo

复制Demo中JZExoPlayer类到你的项目下

implementation 'com.google.android.exoplayer:exoplayer:2.7.1'

Jzvd.setMediaInterface(new JZExoPlayer()); //exo

Jzvd.setJzUserAction(new MyUserActionStd());

/**

* 这只是给埋点统计用户数据用的,不能写和播放相关的逻辑,监听事件请参考MyJzvdStd,复写函数取得相应事件

*/

class MyUserActionStd implements JZUserActionStd {

@Override

public void onEvent(int type, Object url, int screen, Object... objects) {

switch (type) {

case JZUserAction.ON_CLICK_START_ICON:

Log.i("USER_EVENT", "ON_CLICK_START_ICON" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_CLICK_START_ERROR:

Log.i("USER_EVENT", "ON_CLICK_START_ERROR" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_CLICK_START_AUTO_COMPLETE:

Log.i("USER_EVENT", "ON_CLICK_START_AUTO_COMPLETE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_CLICK_PAUSE:

Log.i("USER_EVENT", "ON_CLICK_PAUSE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_CLICK_RESUME:

Log.i("USER_EVENT", "ON_CLICK_RESUME" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_SEEK_POSITION:

Log.i("USER_EVENT", "ON_SEEK_POSITION" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_AUTO_COMPLETE:

Log.i("USER_EVENT", "ON_AUTO_COMPLETE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_ENTER_FULLSCREEN:

Log.i("USER_EVENT", "ON_ENTER_FULLSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_QUIT_FULLSCREEN:

Log.i("USER_EVENT", "ON_QUIT_FULLSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_ENTER_TINYSCREEN:

Log.i("USER_EVENT", "ON_ENTER_TINYSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_QUIT_TINYSCREEN:

Log.i("USER_EVENT", "ON_QUIT_TINYSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_TOUCH_SCREEN_SEEK_VOLUME:

Log.i("USER_EVENT", "ON_TOUCH_SCREEN_SEEK_VOLUME" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserAction.ON_TOUCH_SCREEN_SEEK_POSITION:

Log.i("USER_EVENT", "ON_TOUCH_SCREEN_SEEK_POSITION" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserActionStd.ON_CLICK_START_THUMB:

Log.i("USER_EVENT", "ON_CLICK_START_THUMB" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

case JZUserActionStd.ON_CLICK_BLANK:

Log.i("USER_EVENT", "ON_CLICK_BLANK" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen);

break;

default:

Log.i("USER_EVENT", "unknow");

break;

}

}

}

相关函数回调,屏幕状态,播放器状态,事件

在继承JzvdStd之后,可以通过父类的mCurrentState,取得当前的播放状态。

CURRENT_STATE_IDLE 未知状态,指控件被new出来之后什么都没做

CURRENT_STATE_NORMAL 普通状态

CURRENT_STATE_PREPARING 视频准备状态

CURRENT_STATE_PREPARING_CHANGING_URL 播放中切换url的准备状态

CURRENT_STATE_PLAYING 播放中状态

CURRENT_STATE_PAUSE 暂停状态

CURRENT_STATE_AUTO_COMPLETE 自动播放完成状态

CURRENT_STATE_ERROR 错误状态

复写进入播放状态的函数,取得播放状态的回调

onStateNormal 进入普通状态,通常指setUp之后

onStatePreparing 进入准备中状态,就是loading状态

onStatePlaying 进入播放状态

onStatePause 进入暂停状态

onStateError 进入错误状态

onStateAutoComplete 进入自动播放完成状态

全屏、小窗、非全屏分别是不同的实例,在继承JzvdStd后,通过mCurrentScreen变量,取得当前屏幕类型

SCREEN_WINDOW_NORMAL 普通窗口(进入全屏之前的)

SCREEN_WINDOW_LIST 列表窗口(进入全屏之前)

SCREEN_WINDOW_FULLSCREEN 全屏

SCREEN_WINDOW_TINY 小窗

事件

复写onProgress函数,取得每次播放器设置底部seekBar的进度回调

调用changeUrl函数,切换url

复写onClick函数,取得各种按钮的点击事件

复写onTouch函数,取得全屏之后的手势操作

JiaoZiVideoPlayer的功能远不止上述这些,最近我也在深入的研究中,下篇文章会收集一些大家经常遇到的问题写出来帮助大家,大家有什么建议或者问题可以再下方留言。

android媒体播放框架,Android 使用超简单的多媒体播放器JiaoZiVideoPlayer相关推荐

  1. Android媒体播放框架MediaSessionCompat介绍实践

    前言 最近维护项目的时候遇到了MediaSessionCompat框架的音乐播放器,简单搜索记录一下这套实现播放器的结构吧. MediaSession框架简介 我们先来看看如何设计一款音乐播放App的 ...

  2. Android 媒体播放框架MediaSession分析与实践

    版权声明:本文为博主原创文章,未经博主允许不得转载 源码:AnliaLee/BauzMusic 大家要是看到有错误的地方或者有啥好的建议,欢迎留言评论 前言 最近一直在忙着学习和研究音乐播放器,发现介 ...

  3. android 播放器 wav 无法播放,对于Android媒体播放器mp3与wav(For android media player mp3 vs. wav)...

    对于Android媒体播放器mp3与wav(For android media player mp3 vs. wav) 我想知道在Android媒体播放器上加载和播放小wav是否比较快的小文件更快. ...

  4. android播放器1004,Android媒体播放器在从外部网站播放流时出错(1,-1004)

    我试图从我的 Android应用程序中的网站播放音频文件,但它遇到媒体播放器错误(1,-1004). 当我在Windows媒体播放器或vlc播放器中使用它时,流链接工作正常.为什么Android媒体播 ...

  5. 30个最佳和免费的Android媒体播放器

    今天发布的内容有所不同,我们为您介绍了Google Play App Store提供的The Best Android Media Player . 1. MusiXmatch歌词播放器 狂热的音乐爱 ...

  6. Android媒体播放器设计,基于Android系统多媒体播放器的设计与实现

    基于Android系统多媒体播放器的设计与实现 移动互联网自从其出现就以极强的吸引力捕获了全世界的关注,近些年尤以为甚,各类相关产品也随之蓬勃发展,Android智能手机就是其中之一.另外随着科技发展 ...

  7. android媒体播放器设计报告,基于Android的多媒體播放器课程设计报告.doc

    基于Android的多媒體播放器课程设计报告 基于Android的多媒体播放器课程设计报告 (2014-01-02 22:46:52) HYPERLINK "javascript:;&quo ...

  8. android媒体播放器课程设计,基于Android的多媒体播放器课程设计报告

    基于Android的多媒体播放器课程设计报告 p/*/pp源代码. 我希望这篇文章对初学者有帮助. 希望更多的人在网络上共享自己的学习成果./pp*/pp1 .开发环境/ppAndroid是基于Lin ...

  9. android媒体播放器课程设计,基于android的多媒体播放器课程设计报告.doc

    基于android的多媒体播放器课程设计报告.doc /* 附源码.希望此文能帮助到一些新手.也希望更多的人在网络上 分享自己的学习成果.互相交流,扣扣70876398 */ 1. 开发环境 Andr ...

最新文章

  1. 第十三周项目4-数组的排序:冒泡排序
  2. docker安装在服务器的那个位置,docker容器卷通常会放在什么位置
  3. 大数据计算引擎发展的四个阶段
  4. 九度 1462:两船载物问题(01背包)
  5. python框架源码学习
  6. AI工程师职业规划和学习路线完整版
  7. 菜比如我的漫漫react学习路(二)
  8. 密码学基础(三):非对称加密(RSA算法原理)
  9. android儿童模式 htc,HTC自家系统优化工具Boost+ 任何Android手机都可用
  10. 最全的react视频【黑马程序员】--第一章 react介绍
  11. 20160402系统集成管理工程师(test3)
  12. 得到APP之订阅专栏《硅谷来信》和《精英日课》目录
  13. 计算机老师素质能力提升计划要求,教师2021个人素质提升计划范文
  14. 微信支付宝免签约支付方案
  15. Java 程序员,年薪 40W 需要什么水平?
  16. 尤雨溪的5KB petite-vue源码解析
  17. Python随机生成一注双色球彩票
  18. CDI技术第一步 Hello World!
  19. WPS表格 - 数字累加技巧总结
  20. Android开发艺术探索全面解读

热门文章

  1. vtk环境搭建(windowsXP/win7,vtk6.0.0+cmake2.8+vs2010)
  2. mysql udb_MySQL InnoDB的一些参数说明
  3. jq的插件 vue中引用_详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
  4. python标准库模块_Python标准库模块之heapq
  5. 推荐几款爬虫软件与无需编程的数据分析工具
  6. 双清模式无命令_linux性能监控:IO性能监控命令之iotop命令
  7. DVWA通关教程(下)
  8. 计算机算法知识总结,移动笔试知识点之--计算机类-数据结构与算法知识点总结.pdf...
  9. 华为y7可以人脸识别吗_华为手机经常弹出“系统更新”提示,可以不更新吗?看完涨知识了...
  10. npm install --save