IjkPlayer 实现音乐播放(进度条、缓存、是否正在缓冲等)

枚举:

public enum AudioPlayEnum {/**播放空闲*/PLAYER_FREE,/**预缓冲,准备播放中*/PLAYER_PREPARING,/**播放中*/PLAYER_PLAYING,/**播放完毕*/PLAYER_COMPLETE,/**播放暂停*/PLAYER_PAUSE,/**播放错误*/PLAYER_ERROR
}

回调接口

public interface AudioPlayerEvent {/*** 缓存更新* */void onBufferingUpdate(int percent);/*** 是否正在缓冲*/void onBuffering(boolean isBuffering);/*** 播放进度*/void onPlayProgress(long duration,long currPosition);/*** 播放状态改变* @param mStatus 状态*/void onStatusChange(AudioPlayEnum mStatus,int currPlayPotion);
}

抽象类

public abstract class MyAbstractAudioPlayer {AudioPlayerEvent mAudioPlayerEvent;/*** 暂停之后调用,接着上一次播放*/public abstract void reStart();/*** 带资源播放,播放当前资源* @param path path*/public abstract void start(String path);/*** 将整个列表添加到播放列表,如果是未播放状态,则播放第一个* @param pathList 资源列表*/public abstract void start(List<String> pathList);/*** 播放事件监听器* @param event 时间*/public abstract void setAudioPlayerListener(AudioPlayerEvent event);/*** 暂停*/public abstract void pause();/*** 暂停缓存* @param path 路径*/public abstract void stopCacheAndShutdown(String path);/*** 下一首*/public abstract void nextPlay();/*** 上一首*/public abstract void prevPlay();/*** 是否正在播放* @return boolean*/public abstract boolean isPlaying();/*** 当前播放状态* @return AudioPlayEnum*/public abstract AudioPlayEnum getPlayerStatus();/*** 调整进度* @param time 时间*/public abstract void seekTo(long time);/*** 拖动进度条,通知(防止拖动时Timmer跑进度条)*/public abstract void seekStart();/*** 释放播放器*/public abstract void release();/*** 获取当前播放的位置* @return 获取当前播放的位置*/public abstract long getCurrentPosition();/*** 获取视频总时长* @return long*/public abstract long getDuration();/*** 获取缓冲百分比* @return int*/public abstract int getBufferedPercentage();/*** 设置列表是否循环播放* @param isLooping 循环*/public abstract void setListLooping(boolean isLooping);/*** 设置是否单曲循环* @param isLooping 循环*/public abstract void setSingleLooping(boolean isLooping);
}

该类实现对电话监听

/*** 自定义内部类对来电的电话状态进行监听* @author chenpin*/
public class MyPhoneStateListener extends PhoneStateListener {private MyAudioManager mMyAudioManager;/**记录来电时,是否在播放状态,在电话空闲时恢复*/private boolean mAudioPlayingWhenCallRinging = false;MyPhoneStateListener(MyAudioManager mMyAudioManager) {this.mMyAudioManager = mMyAudioManager;}@Overridepublic void onCallStateChanged(int state, String incomingNumber) {super.onCallStateChanged(state, incomingNumber);if (mMyAudioManager == null) {return;}switch (state) {case TelephonyManager.CALL_STATE_RINGING:case TelephonyManager.CALL_STATE_OFFHOOK:if(mMyAudioManager.isPlaying()){mAudioPlayingWhenCallRinging = true;mMyAudioManager.pause();}else{mAudioPlayingWhenCallRinging = false;}break;case TelephonyManager.CALL_STATE_IDLE://打完电话mMyAudioManager.reStart();break;default:break;}}
}

封装AndroidVideoCache缓存类

/*** @author chenpin*/
public class AudioCacheManager {/*** 最大缓存容量*/private static final long DEFAULT_MAX_SIZE = 200 * 1024 * 1024;/***  最大缓存数量*/private static final int DEFAULT_MAX_FILE_COUNT = 20;/*** SD卡APP保存文件名*/private static final String SD_SAVE_PATH = "appName";@SuppressLint("SdCardPath")private static final String APP_SAVE_PATH = "/data/data/";private static final String SAVE_AUDIO_PATH = "audio_cache";private static AudioCacheManager mInstance;private static HttpProxyCacheServer mCacheServer;private CacheListener mCacheListener;public static AudioCacheManager getInstance(Context context) {Context applicationContext = context.getApplicationContext();if (null == mInstance) {synchronized (AudioCacheManager.class) {if (null == mInstance) {mInstance = new AudioCacheManager(applicationContext);}}}return mInstance;}private AudioCacheManager(Context context) {File cacheDir = getCacheDirectory(context);Md5FileNameGenerator md5FileNameGenerator = new Md5FileNameGenerator();HttpProxyCacheServer.Builder builder = new HttpProxyCacheServer.Builder(context).maxCacheFilesCount(DEFAULT_MAX_FILE_COUNT).cacheDirectory(cacheDir).fileNameGenerator(md5FileNameGenerator);mCacheServer = builder.build();}static HttpProxyCacheServer getProxy(Context context) {return mCacheServer == null ? (mCacheServer = newProxy(context)) : mCacheServer;}private static HttpProxyCacheServer newProxy(Context context) {return new HttpProxyCacheServer.Builder(context).maxCacheSize(DEFAULT_MAX_SIZE).build();}private File getCacheDirectory(Context context) {File cacheParentDir = getCacheParentDirectory(context);File cacheDir = new File(cacheParentDir, SAVE_AUDIO_PATH);if (!cacheDir.exists()) {cacheDir.mkdirs();}return cacheDir;}private File getCacheParentDirectory(Context context) {File appCacheDir = null;String externalStorageState;try {externalStorageState = Environment.getExternalStorageState();} catch (NullPointerException e) {externalStorageState = "";}if (MEDIA_MOUNTED.equals(externalStorageState)) {appCacheDir = getExternalCacheDir(context);}if (appCacheDir == null) {appCacheDir = context.getCacheDir();}if (appCacheDir == null) {String cacheDirPath = APP_SAVE_PATH+ context.getPackageName()+ File.separator+SAVE_AUDIO_PATH+File.separator;appCacheDir = new File(cacheDirPath);}return appCacheDir;}private static File getExternalCacheDir(Context context) {String pathPrix = Environment.getExternalStorageDirectory() + "/";File file = new File(pathPrix + SD_SAVE_PATH);if (!file.exists()) {file.mkdirs();}return file;}String getProxyUrl(String url) {return mCacheServer.getProxyUrl(url);}void registerCacheListener(String url, CacheListener listener) {mCacheListener = listener;mCacheServer.registerCacheListener(listener, url);}void unregisterCacheListener() {mCacheServer.unregisterCacheListener(mCacheListener);}
}

主要代码,音频管理类:

//音频管理类
/*** 集成IjkPlayer音頻播放** @author chenpin*/
public class MyAudioManager extends MyAbstractAudioPlayer {public static final String TEST_MP3_URL = "http:XXX.mp3";/*** 定时器检测播放进度时间间隔*/private final int TIMER_PROGRESS_INTERVAL = 200;/*** 最大连续播放错误数*/private static final int MAX_CONTINUE_ERROR_NUM = 3;private IjkMediaPlayer mMediaPlayer;private Context mContext;private Context appContext;/*** 播放错误次数,连续三次错误,则不进行下一次播放了*/private int mErrorPlayNum = 0;/*** 播放路径资源存储*/private List<String> mDataSourceList = new ArrayList<>();/*** 播放位置存储*/private int currPlayPotion = -1;/*** 是否列表循环播放*/private boolean mListLooping = false;/*** 是否单曲循环*/private boolean mSingleLooping = false;/*** 缓存百分比*/private int mBufferedPercent;/*** 是否正在拖动进度条*/private boolean mSeekTouch = false;/*** 监听播放器进度Timer以及Task*/private Timer mProgressTimer;private TimerTask mProgressTask;private final Object mProgressLock = new Object();/*** 进度线程活动*/private boolean mAudioStateAlive = true;/*** 音频缓存*/private HttpProxyCacheServer mCacheServer;/*** 记录上一次播放进度,用于判断是否正在缓冲*/private long prevPlayPosition;/*** 电话管理者对象*/private TelephonyManager mTelephonyManager;/*** 电话状态监听者*/private MyPhoneStateListener myPhoneStateListener;/*** 用于发送是否在缓冲的消息Handler*/private Handler mBufferHandler = new Handler(Looper.getMainLooper());/*** 当前播放器状态* */private AudioPlayEnum mPlayerStatus = AudioPlayEnum.PLAYER_FREE;public MyAudioManager(Context context) {mContext = context;appContext = context.getApplicationContext();initPlayer();}private void initPlayer() {//初始化mMediaPlayer = new IjkMediaPlayer(mContext);mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);//缓存文件的路径
//        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "cache_file_path", path);//添加监听mMediaPlayer.setOnErrorListener(onErrorListener);mMediaPlayer.setOnCompletionListener(onCompletionListener);mMediaPlayer.setOnInfoListener(onInfoListener);mMediaPlayer.setOnBufferingUpdateListener(onBufferingUpdateListener);mMediaPlayer.setOnPreparedListener(onPreparedListener);//来电监听mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);myPhoneStateListener = new MyPhoneStateListener(this);mTelephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);}/*** 播放*/private void prepareAsync(int position, String path) {try {mMediaPlayer.reset();sendPlayerStatus(AudioPlayEnum.PLAYER_PREPARING);mCacheServer = AudioCacheManager.getProxy(appContext);AudioCacheManager.getInstance(appContext).registerCacheListener(path, new CacheListener() {@Overridepublic void onCacheAvailable(File file, String s, int i) {mBufferedPercent = i;if (mAudioPlayerEvent != null) {mAudioPlayerEvent.onBufferingUpdate(mBufferedPercent);}}});String proxyPath = AudioCacheManager.getInstance(appContext).getProxyUrl(path);if (mCacheServer.isCached(path)|| proxyPath.startsWith("file://")|| proxyPath.startsWith("/storage/emulated/0/")) {mBufferedPercent = 100;if (mAudioPlayerEvent != null) {sendBufferingHandler(true, false);}//不要在这里发进度,上层调用不到duration,设置不了max} else {mBufferedPercent = 0;if (mAudioPlayerEvent != null) {sendBufferingHandler(false, true);}}mMediaPlayer.setDataSource(proxyPath);mMediaPlayer.prepareAsync();currPlayPotion = position;} catch (Exception e) {e.printStackTrace();onErrorPlay();}}@Overridepublic void reStart() {if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {sendPlayerStatus(AudioPlayEnum.PLAYER_PLAYING);mMediaPlayer.start();synchronized (mProgressLock) {mProgressLock.notifyAll();}}}@Overridepublic void start(String path) {if(!StringUtils.isEmpty(path)){List<String> pathList = new ArrayList<>();pathList.add(path);start(pathList);}}@Overridepublic void start(List<String> pathList) {if (pathList == null || pathList.isEmpty()) {return;}mDataSourceList.clear();mDataSourceList.addAll(pathList);prepareAsync(0, mDataSourceList.get(0));}@Overridepublic void setAudioPlayerListener(AudioPlayerEvent event) {this.mAudioPlayerEvent = event;}@Overridepublic void pause() {try {if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {sendBufferingHandler(true, false);sendPlayerStatus(AudioPlayEnum.PLAYER_PAUSE);mMediaPlayer.pause();}} catch (IllegalStateException e) {e.printStackTrace();}}@Overridepublic void stopCacheAndShutdown(String path) {if (mCacheServer != null && !StringUtils.isEmpty(path)) {mCacheServer.stopCacheAndShutdown(path);}}@Overridepublic void nextPlay() {if (mDataSourceList.isEmpty()) {return;}if (currPlayPotion < 0) {prepareAsync(0, mDataSourceList.get(0));} else {if (mDataSourceList.size() > currPlayPotion + 1) {prepareAsync(currPlayPotion + 1, mDataSourceList.get(currPlayPotion + 1));} else {if (mListLooping) {prepareAsync(0, mDataSourceList.get(0));}}}}@Overridepublic void prevPlay() {if (mDataSourceList.isEmpty() || currPlayPotion < 0) {return;}if (currPlayPotion == 0) {if (mListLooping) {prepareAsync(mDataSourceList.size() - 1, mDataSourceList.get(mDataSourceList.size() - 1));}} else {prepareAsync(currPlayPotion - 1, mDataSourceList.get(currPlayPotion - 1));}}@Overridepublic boolean isPlaying() {if (mMediaPlayer != null) {return mMediaPlayer.isPlaying();}return false;}@Overridepublic AudioPlayEnum getPlayerStatus() {return mPlayerStatus;}@Overridepublic void seekTo(long time) {try {if (mMediaPlayer != null) {mMediaPlayer.seekTo(time);mSeekTouch = false;if (mMediaPlayer.isPlaying()) {synchronized (mProgressLock) {mProgressLock.notifyAll();}}}} catch (Exception e) {e.printStackTrace();}}@Overridepublic void seekStart() {mSeekTouch = true;}@Overridepublic void release() {mTelephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_NONE);mBufferHandler.removeCallbacksAndMessages(null);if (mCacheServer != null) {AudioCacheManager.getInstance(appContext).unregisterCacheListener();mCacheServer.shutdown();}if (mMediaPlayer != null) {mMediaPlayer.stop();mAudioStateAlive = false;currPlayPotion = -1;mMediaPlayer.release();}}@Overridepublic long getCurrentPosition() {return mMediaPlayer.getCurrentPosition();}@Overridepublic long getDuration() {return mMediaPlayer.getDuration();}@Overridepublic int getBufferedPercentage() {return mBufferedPercent;}@Overridepublic void setListLooping(boolean isLooping) {mListLooping = isLooping;}@Overridepublic void setSingleLooping(boolean isLooping) {mSingleLooping = isLooping;}/*** 销毁Tmmer*/private void destroyTimer() {if (mProgressTimer != null) {mProgressTimer.cancel();mProgressTimer = null;}}/*** 错误时,自动播放下一首*/private void onErrorPlay() {sendPlayerStatus(AudioPlayEnum.PLAYER_ERROR);destroyTimer();if (mErrorPlayNum < MAX_CONTINUE_ERROR_NUM) {mErrorPlayNum++;if (mSingleLooping) {//单曲循环prepareAsync(currPlayPotion, mDataSourceList.get(currPlayPotion));} else if (mListLooping || mDataSourceList.size() < currPlayPotion + 1) {//列表循环nextPlay();}}}/*** 延时发送是否在缓冲的状态,防止假缓冲*/private void sendBufferingHandler(boolean sendNow, final boolean isBuffering) {if (mAudioPlayerEvent != null) {mAudioPlayerEvent.onBuffering(isBuffering);}/*mBufferHandler.removeCallbacksAndMessages(null);mBufferHandler.postDelayed(new Runnable() {@Overridepublic void run() {if (mAudioPlayerEvent != null) {mAudioPlayerEvent.onBuffering(isBuffering);}}}, sendNow ? 0 : (long) (2.5 * TIMER_PROGRESS_INTERVAL));*/}/*** 设置当前播放状态*/private void sendPlayerStatus(AudioPlayEnum mStatus){mPlayerStatus = mStatus;if(mAudioPlayerEvent != null){mAudioPlayerEvent.onStatusChange(mPlayerStatus,currPlayPotion);}}/*** 定时器检测播放进度*/private void playProgressListener() {if (mProgressTimer == null) {mProgressTimer = new Timer();}if (mProgressTask != null) {mProgressTask.cancel();mProgressTask = null;}mProgressTask = new TimerTask() {@Overridepublic void run() {while (mAudioStateAlive) {if (mMediaPlayer == null|| !mMediaPlayer.isPlaying()|| mSeekTouch) {synchronized (mProgressLock) {try {mProgressLock.wait();} catch (InterruptedException e) {e.printStackTrace();}}} else {try {Thread.sleep(TIMER_PROGRESS_INTERVAL);} catch (InterruptedException e) {e.printStackTrace();}}if (mAudioPlayerEvent != null&& !mSeekTouch&& mMediaPlayer.isPlaying()&& mMediaPlayer != null) {long currPosition = mMediaPlayer.getCurrentPosition();//播放之前的缓冲在onPrepare时已经缓冲完了,所以这里要排除进度为0if (currPosition != 0 && prevPlayPosition >= currPosition) {sendBufferingHandler(false, true);} else {sendBufferingHandler(true, false);}prevPlayPosition = currPosition;mAudioPlayerEvent.onPlayProgress(mMediaPlayer.getDuration(), currPosition);}}}};mProgressTimer.schedule(mProgressTask, 0);}private IMediaPlayer.OnErrorListener onErrorListener = new IMediaPlayer.OnErrorListener() {@Overridepublic boolean onError(IMediaPlayer iMediaPlayer, int frameworkErr, int implErr) {sendBufferingHandler(true, false);onErrorPlay();LogUtils.e(frameworkErr + "==>chenpin error" + implErr);return true;}};private IMediaPlayer.OnInfoListener onInfoListener = new IMediaPlayer.OnInfoListener() {@Overridepublic boolean onInfo(IMediaPlayer iMediaPlayer, int what, int extra) {return true;}};private IMediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() {@Overridepublic void onBufferingUpdate(IMediaPlayer iMediaPlayer, int percent) {}};private IMediaPlayer.OnPreparedListener onPreparedListener = new IMediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(IMediaPlayer iMediaPlayer) {if (mAudioPlayerEvent != null) {synchronized (mProgressLock) {mProgressLock.notifyAll();}mErrorPlayNum = 0;//准备完毕后发送一次缓存(有可能已经缓存完毕)mAudioPlayerEvent.onBufferingUpdate(mBufferedPercent);//当前正播放,播放器已经预缓存完毕,开始播放了sendBufferingHandler(true, false);//记录并发送当前播放状态sendPlayerStatus(AudioPlayEnum.PLAYER_PLAYING);//开始监听播放进度playProgressListener();}}};private IMediaPlayer.OnCompletionListener onCompletionListener = new IMediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(IMediaPlayer iMediaPlayer) {//播放完毕if (mAudioPlayerEvent != null) {prevPlayPosition = 0;sendPlayerStatus(AudioPlayEnum.PLAYER_COMPLETE);destroyTimer();if (mSingleLooping) {//单曲循环prepareAsync(currPlayPotion, mDataSourceList.get(currPlayPotion));} else if (mListLooping || mDataSourceList.size() < currPlayPotion + 1) {//列表循环nextPlay();}}}};
}

实现代码:

//该处按钮监听
if (v == nextIcon) {//下一首myAudioManager.nextPlay();
} else if (v == playStatusIcon) {//播放状态图标if (myAudioManager.isPlaying()) {myAudioManager.pause();} else if (myAudioManager.getPlayerStatus() == AudioPlayEnum.PLAYER_PAUSE) {myAudioManager.reStart();} else {List<String> list = new ArrayList<>();list.add(TEST_MP3_URL);list.add(TEST_MP3_URL);list.add(TEST_MP3_URL);myAudioManager.start(list);}
} else if (v == listLoopTxt || v == listLoopTxtWhenScroll) {//循环myAudioManager.setListLooping(true);
}

//如何使用回调(这里用seekbar来接收进度)

myAudioManager.setAudioPlayerListener(new AudioPlayerEvent() {@Overridepublic void onBufferingUpdate(final int percent) {runOnUiThread(new Runnable() {@Overridepublic void run() {int max = (int) (myAudioManager.getDuration());if (max > 0) {seekBar.setMax(max);seekBar.setSecondaryProgress(max * percent / 100);}}});}@Overridepublic void onBuffering(final boolean isBuffering) {runOnUiThread(new Runnable() {@Overridepublic void run() {
//                        title.setText(isBuffering ? "正在缓冲..." : "缓冲完毕");}});}@Overridepublic void onPlayProgress(final long duration, final long currPosition) {runOnUiThread(new Runnable() {@Overridepublic void run() {seekBar.setMax((int) duration);seekBar.setProgress((int) currPosition);}});}@Overridepublic void onStatusChange(AudioPlayEnum mStatus, int currPlayPotion) {//状态改变,会在这回调,可以更新上层播放UI等}});

}

//seekbar监听,(注意一定要在开始触摸的时候调用seekStart方法,否则会导致进度条回退)

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {myAudioManager.seekStart();}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {int progress = seekBar.getProgress();myAudioManager.seekTo(progress);}
});

在ondestory中销毁

@Override
protected void onDestroy() {super.onDestroy();if (myAudioManager != null) {myAudioManager.release();}
}

这个功能集成在项目里,没有单独弄出来上传资源了

IjkPlayer+AndroidVideoCache 实现音乐播放相关推荐

  1. 搬砖之路----MusicPlayer 一个基于Vlc(2.0+)开发的android音乐播放器--浅析在android开发过程中播放器选择之路!

    前言 MusicPlayer 是一款基于vlc播放器开发的一个音乐播放器,你也可以理解为在此核心上的搬砖之路,核心的内容并不是我写的,因此在正式写blog之前,感谢那些vlc核心的开发人员让我用到这么 ...

  2. 乐乐音乐:Android音乐播放器及动感(KTV)歌词相关博客汇总

    相关简介 Java Swing PC版本乐乐音乐播放器 乐乐音乐PC播放器单机版本,支持ape,wav,flac,mp3等多种格式,支持动态ksc.hrc.krc歌词文件和支持和显示翻译歌词和音译歌词 ...

  3. 单片AT89C2051 + SD卡 + 3310LCD = 音乐播放器

    http://www.amobbs.com/thread-4503884-1-1.html 这个小玩意,采用 ATMEL 的传统51MCU作主控制芯片,加上SD卡和显示屏,就可以作简单的音乐播放器了, ...

  4. android手机播放pc音乐播放器,最强手机音乐播放器?Foobar2K安卓版体验

    说到最强大的PC音乐播放器,相信很多朋友,特别是HiFi发烧友,会把选票投给Foobar2000.的确,在PC平台上,Foobar2000的优势非常巨大.例如它能够自由定制界面,虽然原生界面很简陋,但 ...

  5. arduino下载库出错_【arduino】DIY音乐播放器,arduino播放wav音乐,TRMpcm库测试及使用...

    微信关注 "DLGG创客DIY"设为"星标",重磅干货,第一时间送达. arduino特点库超多,想必大家都领教了,今天来分享一下之前玩过的TRMpcm库. 这 ...

  6. android 系统锁屏音乐播放器,Android实现音乐播放器锁屏页

    本文实例为大家分享了Android音乐播放器锁屏页的具体代码,供大家参考,具体内容如下 首页我们先看一下效果图 下边来说一下实现逻辑,其主要思路就是新建一个activity使其覆盖在锁屏页上边. 一. ...

  7. 从零开始撸音乐播放器(源码可下载)

    演示视频 哈哈,自己是真的弱.被生活狠狠打脸了. Java课设要搞音乐播放器.然而老师只讲了输入输出啥的,其他自学. 从零开始撸代码. 1 .从sound,到AppletPlayer又到Player. ...

  8. 编写音乐播放器的一些感想

    编写音乐播放器的一些感想 当初是想着学习C#,就动手开始实现一个简单的播放器.在实现的工程中发现自己能够学到很多东西,就有了把播放器用c++重写的想法,在实现过程中,发现c++想实现c#同样的功能,真 ...

  9. Linux开发板怎么用madplay,Linux中madplay 音乐播放器移植步骤

    madplay 音乐播放器移植步骤 madplay版本: madplay-0.15.2 交叉编译器版本: arm-linux-gcc 3.4.1 操作系统平台: Linux -- Red Hat 9. ...

最新文章

  1. 蚂蚁森林合种计划(2020.12.19更新,7天有效)
  2. bash脚本之for语句if语句以及各种测试语句(2)
  3. 在Android中使用AspectJ进行切面编程的简易步骤
  4. python 递归 分叉_浅谈Python 递归算法指归
  5. keil for 51 汉字显示问题
  6. Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法...
  7. 用asp.net获取服务器和客服端有关信息
  8. 使用solrj api操作solr
  9. 关于C++中的继承感悟
  10. 【C++】结构体变量与结构体指针大小区别(Socket sendto函数)
  11. 读书笔记:自动控制原理
  12. L2UWE: A Framework for the Efficient Enhancement of Low-Light Underwater Images阅读札记
  13. osgEarth示例分析——osgearth_manip
  14. 2108 JAVASE每日复习总结 链接汇总
  15. Delayed Adversarial Training with Non-Sequential Adversarial Epochs
  16. 2022安全员-A证考试题模拟考试题库模拟考试平台操作
  17. UG编程-适合新手的详细讲解
  18. HTML页面添加背景音乐
  19. 翻译考试用计算机作答,法语考试:全国翻译专业资格(水平)考试(CATTI)介绍
  20. 百度ERNIE-Gram: Pre-Training with Explicitly N-Gram Masked Language Modeling

热门文章

  1. Windows以服务方式运行Java程序
  2. tyvj2032(超级源点)
  3. 【委内瑞拉石油币Petro仍未进入二级市场】
  4. 电源完整性仿真流程梳理
  5. 测试网口故障的方法-回环水晶头及实验方法
  6. TTU智能配电终端_金智科技:新一代智能终端研制成功,即将发力泛在电力物联网建设【安信电新】...
  7. BDC录屏 EPIC_PROC,银企直连
  8. 计算机毕业设计Java计算机组成原理教学网站(源码+系统+mysql数据库+lw文档)
  9. 文章管理系统 -- Express学习
  10. 期权波动率“微笑曲线”之谜