在此感谢鸿洋大神,因为我这是在慕课上看大神的视频做出来的。

代码中我已经添加了很多很多注释,不光是为了大家,也是为了自己能够更加透彻的理解该功能

支持原创,也不算原创了哈哈~

http://blog.csdn.net/lhk147852369/article/details/78658055

注意注意:

Android 6.0动态获取录音权限,我并没有加上,所以你们需要在写完代码后,运行时在权限管理中指定该权限

否则会崩溃哦~~, 当然你们可以改变as中的targerversion<23就可以了

话不多说,直接上效果图:

MainActivity :

public class MainActivity extends AppCompatActivity {private ListView mListView;private ArrayAdapter<Recorder> mAdapter;private List<Recorder> mDatas =new ArrayList<>();private AudioRecorderButton mAudioRecorderButton;private View mAnimView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();setListViewAdapter();}private void initView(){mListView = findViewById(R.id.id_listview);mAudioRecorderButton = findViewById(R.id.id_recorder_button);mAudioRecorderButton.setAudioFinishRecorderListener(new AudioRecorderButton.AudioFinishRecorderListener() {@Overridepublic void onFinish(float seconds, String filePath) {//每完成一次录音Recorder recorder = new Recorder(seconds,filePath);mDatas.add(recorder);//更新adaptermAdapter.notifyDataSetChanged();//设置listview 位置mListView.setSelection(mDatas.size()-1);}});}private void setListViewAdapter(){mAdapter = new RecorderAdapter(this, mDatas);mListView.setAdapter(mAdapter);mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {//如果第一个动画正在运行, 停止第一个播放其他的if (mAnimView != null) {mAnimView.setBackgroundResource(R.drawable.adj);mAnimView = null;}//播放动画mAnimView = view.findViewById(R.id.id_recorder_anim);mAnimView.setBackgroundResource(R.drawable.play_anim);AnimationDrawable animation = (AnimationDrawable) mAnimView.getBackground();animation.start();//播放音频  完成后改回原来的backgroundMediaManager.playSound(mDatas.get(position).filePath, new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {mAnimView.setBackgroundResource(R.drawable.adj);}});}});}/*** 根据生命周期 管理播放录音*/@Overrideprotected void onPause() {super.onPause();MediaManager.pause();}@Overrideprotected void onResume() {super.onResume();MediaManager.resume();}@Overrideprotected void onDestroy() {super.onDestroy();MediaManager.release();}//数据类class Recorder{float time;String filePath;public float getTime() {return time;}public void setTime(float time) {this.time = time;}public String getFilePath() {return filePath;}public void setFilePath(String filePath) {this.filePath = filePath;}public Recorder(float time, String filePath) {super();this.time = time;this.filePath = filePath;}}
}

主页面:

需要注意:改下自定义button的包名哦,不然会找不到的

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.lgoutech.weixin_recorder.MainActivity"><ListViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/id_listview"android:background="#ebebeb"android:divider="@null"android:dividerHeight="10dp"></ListView><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><Viewandroid:layout_width="wrap_content"android:layout_height="1dp"android:background="#ccc"/><com.lgoutech.weixin_recorder.view.AudioRecorderButtonandroid:id="@+id/id_recorder_button"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="50dp"android:layout_marginRight="50dp"android:gravity="center"android:layout_marginTop="7dp"android:layout_marginBottom="7dp"android:padding="5dp"android:text="@string/str_recorder_normal"android:textColor="#727272"android:background="@drawable/btn_recorder_normal"android:minHeight="0dp"></com.lgoutech.weixin_recorder.view.AudioRecorderButton></LinearLayout>
</LinearLayout>

自定义的dialog、xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:padding="20dp"android:gravity="center"android:background="@drawable/dialog_loading_bg"tools:context="com.lgoutech.weixin_recorder.MainActivity"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><ImageViewandroid:id="@+id/id_recorder_dialog_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/recorder"android:visibility="visible"/><ImageViewandroid:id="@+id/id_recorder_dialog_voice"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/v1"android:visibility="visible"/></LinearLayout><TextViewandroid:id="@+id/id_recorder_dialog_label"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="手指上划,取消发送"android:textColor="#FFFFFF"/>
</LinearLayout>

ListView的Item布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="60dp"android:layout_marginTop="5dp"tools:context="com.lgoutech.weixin_recorder.MainActivity"><ImageViewandroid:id="@+id/id_icon"android:layout_width="40dp"android:layout_height="40dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginRight="5dp"android:src="@drawable/icon"/><LinearLayoutandroid:id="@+id/id_recorder_length"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:orientation="vertical"android:layout_toLeftOf="@id/id_icon"android:background="@drawable/chatto_bg_focused"><Viewandroid:id="@+id/id_recorder_anim"android:layout_width="25dp"android:layout_height="25dp"android:layout_gravity="center_vertical|right"android:background="@drawable/adj"/></LinearLayout><TextViewandroid:id="@+id/id_recorder_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toLeftOf="@id/id_recorder_length"android:layout_marginRight="3dp"android:textColor="#ff777777"android:layout_centerVertical="true"/></RelativeLayout>

录音管理类:

public class AudioManager {private MediaRecorder mMediaRecorder;private String mDir;private String mCurrentFilePath;private static AudioManager mInstance;private boolean isPrepared;public AudioManager(String dir){mDir = dir;};/*** 回调准备完毕*/public interface AudioStateListener {void wellPrepared();}public AudioStateListener mListener;public void setOnAudioStateListener(AudioStateListener listener){mListener = listener;}public static AudioManager getInstance(String dir){if (mInstance == null) {synchronized (AudioManager.class) {if (mInstance == null) {mInstance = new AudioManager(dir);}}}return mInstance;}/*** 准备*/public void prepareAudio() {try {isPrepared = false;File dir = new File(mDir);if (!dir.exists()) {dir.mkdir();}String fileName = generateFileName();File file = new File(dir, fileName);mCurrentFilePath = file.getAbsolutePath();mMediaRecorder = new MediaRecorder();//设置输出文件mMediaRecorder.setOutputFile(file.getAbsolutePath());//设置MediaRecorder的音频源为麦克风mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置音频格式mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);//设置音频的格式为amrmMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);mMediaRecorder.prepare();mMediaRecorder.start();//准备结束isPrepared = true;if (mListener != null) {mListener.wellPrepared();}} catch (IOException e) {e.printStackTrace();}}//    生成UUID唯一标示符
//    算法的核心思想是结合机器的网卡、当地时间、一个随即数来生成GUID
//    .amr音频文件private String generateFileName() {return UUID.randomUUID().toString()+".amr";}public int getVoiceLevel(int maxLevel) {if (isPrepared) {//获得最大的振幅getMaxAmplitude() 1-32767try {return maxLevel * mMediaRecorder.getMaxAmplitude()/32768+1;} catch (Exception e) {}}return 1;}public void release() {mMediaRecorder.stop();mMediaRecorder.release();mMediaRecorder = null;}public void cancel(){release();if(mCurrentFilePath!=null) {File file = new File(mCurrentFilePath);file.delete();mCurrentFilePath = null;}}public String getCurrentFilePath() {return mCurrentFilePath;}
}

最重要的自定义按钮,很多逻辑都在这里:

/*** 自定义按钮 实现录音等功能* Created by Administrator on 2017/11/28.*/@SuppressLint("AppCompatCustomView")
public class AudioRecorderButton extends Button implements AudioManager.AudioStateListener {//手指滑动 距离private static final int DISTANCE_Y_CANCEL = 50;//状态private static final int STATE_NORMAL = 1;private static final int STATE_RECORDING = 2;private static final int STATE_WANT_TO_CANCEL = 3;//当前状态private int mCurState = STATE_NORMAL;//已经开始录音private boolean isRecording = false;private DialogManager mDialogManager;private AudioManager mAudioManager;private float mTime;//是否触发onlongclickprivate boolean mReady;public AudioRecorderButton(Context context) {this(context, null);}public AudioRecorderButton(Context context, AttributeSet attrs) {super(context, attrs);mDialogManager = new DialogManager(getContext());//偷个懒,并没有判断 是否存在, 是否可读。String dir = Environment.getExternalStorageDirectory() + "/recorder_audios";mAudioManager = new AudioManager(dir);mAudioManager.setOnAudioStateListener(this);//按钮长按 准备录音 包括startsetOnLongClickListener(new OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {mReady = true;mAudioManager.prepareAudio();return false;}});}/*** 录音完成后的回调*/public interface AudioFinishRecorderListener{//时长  和 文件void onFinish(float seconds,String filePath);}private AudioFinishRecorderListener mListener;public void setAudioFinishRecorderListener (AudioFinishRecorderListener listener){mListener = listener;}//获取音量大小的Runnableprivate Runnable mGetVoiceLevelRunnable = new Runnable() {@Overridepublic void run() {while (isRecording) {try {Thread.sleep(100);mTime += 0.1;mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);} catch (InterruptedException e) {e.printStackTrace();}}}};private static final int MSG_AUDIO_PREPARED = 0X110;private static final int MSG_VOICE_CHANGED = 0X111;private static final int MSG_DIALOG_DIMISS = 0X112;private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_AUDIO_PREPARED ://TODO 真正现实应该在audio end prepared以后mDialogManager.showRecordingDialog();isRecording = true;new Thread(mGetVoiceLevelRunnable).start();break;case MSG_VOICE_CHANGED :mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));break;case MSG_DIALOG_DIMISS :mDialogManager.dimissDialog();break;}}};@Overridepublic void wellPrepared() {mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);}@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();int x = (int) event.getX();int y = (int) event.getY();switch (action) {case MotionEvent.ACTION_DOWN://TODOisRecording = true;changeState(STATE_RECORDING);break;case MotionEvent.ACTION_MOVE:if (isRecording) {//根据想x,y的坐标,判断是否想要取消if (wantToCancel(x, y)) {changeState(STATE_WANT_TO_CANCEL);} else {changeState(STATE_RECORDING);}}break;case MotionEvent.ACTION_UP://如果longclick 没触发if (!mReady) {reset();return super.onTouchEvent(event);}//触发了onlongclick 没准备好,但是已经prepared 已经start//所以消除文件夹if(!isRecording||mTime<0.6f){mDialogManager.tooShort();mAudioManager.cancel();mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);}else if(mCurState==STATE_RECORDING){//正常录制结束mDialogManager.dimissDialog();mAudioManager.release();if (mListener != null) {mListener.onFinish(mTime,mAudioManager.getCurrentFilePath());}}else if (mCurState == STATE_RECORDING) {mDialogManager.dimissDialog();//release//callbacktoAct} else if (mCurState == STATE_WANT_TO_CANCEL) {mDialogManager.dimissDialog();mAudioManager.cancel();//cancel}reset();break;}return super.onTouchEvent(event);}/*** 恢复状态 标志位*/private void reset() {isRecording = false;mReady = false;changeState(STATE_NORMAL);mTime = 0;}private boolean wantToCancel(int x, int y) {//如果左右滑出 buttonif (x < 0 || x > getWidth()) {return true;}//如果上下滑出 button  加上我们自定义的距离if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {return true;}return false;}//改变状态private void changeState(int state) {if (mCurState != state) {mCurState = state;switch (state) {case STATE_NORMAL:setBackgroundResource(R.drawable.btn_recorder_normal);setText(R.string.str_recorder_normal);break;case STATE_RECORDING:setBackgroundResource(R.drawable.btn_recording);setText(R.string.str_recorder_recording);if (isRecording) {mDialogManager.recording();}break;case STATE_WANT_TO_CANCEL:setBackgroundResource(R.drawable.btn_recording);setText(R.string.str_recorder_want_cancel);mDialogManager.wantToCancel();break;}}}}

Dialog管理类:

public class DialogManager {private Dialog mDialog;private ImageView mIcon;private ImageView mVoice;private TextView mLable;private Context mContext;public DialogManager(Context context){mContext = context;}public void showRecordingDialog(){mDialog = new Dialog(mContext, R.style.Theme_AudioDialog);LayoutInflater inflater = LayoutInflater.from(mContext);View view=inflater.inflate(R.layout.dialog_recorder,null);mDialog.setContentView(view);mIcon = view.findViewById(R.id.id_recorder_dialog_icon);mVoice = view.findViewById(R.id.id_recorder_dialog_voice);mLable = view.findViewById(R.id.id_recorder_dialog_label);mDialog.show();}//正在播放时的状态public void recording() {if (mDialog != null&&mDialog.isShowing()) {mIcon.setVisibility(View.VISIBLE);mVoice.setVisibility(View.VISIBLE);mLable.setVisibility(View.VISIBLE);mIcon.setImageResource(R.drawable.recorder);mLable.setText("手指上划,取消发送");}}//想要取消public void wantToCancel(){if (mDialog != null&&mDialog.isShowing()) {mIcon.setVisibility(View.VISIBLE);mVoice.setVisibility(View.GONE);mLable.setVisibility(View.VISIBLE);mIcon.setImageResource(R.drawable.cancel);mLable.setText("松开手指,取消发送");}}//录音时间太短public void tooShort() {if (mDialog != null&&mDialog.isShowing()) {mIcon.setVisibility(View.VISIBLE);mVoice.setVisibility(View.GONE);mLable.setVisibility(View.VISIBLE);mIcon.setImageResource(R.drawable.voice_to_short);mLable.setText("录音时间过短");}}//关闭dialogpublic void dimissDialog(){if (mDialog != null&&mDialog.isShowing()) {mDialog.dismiss();mDialog = null;}}/*** 通过level更新voice上的图片** @param level*/public void updateVoiceLevel(int level){if (mDialog != null&&mDialog.isShowing()) {int resId = mContext.getResources().getIdentifier("v" + level, "drawable", mContext.getPackageName());mVoice.setImageResource(resId);}}
}

播放录音类:

/*** Created by Administrator on 2017/11/28.* 播放录音类*/public class MediaManager {private static MediaPlayer mMediaPlayer;private static boolean isPause;//播放录音public static void playSound(String filePath, MediaPlayer.OnCompletionListener onCompletionListener){if (mMediaPlayer == null) {mMediaPlayer = new MediaPlayer();//播放错误 防止崩溃mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {mMediaPlayer.reset();return false;}});}else{mMediaPlayer.reset();}try {mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mMediaPlayer.setOnCompletionListener(onCompletionListener);mMediaPlayer.setDataSource(filePath);mMediaPlayer.prepare();mMediaPlayer.start();} catch (IOException e) {e.printStackTrace();}}/*** 如果 播放时间过长,如30秒* 用户突然来电话了,则需要暂停*/public static void pause() {if (mMediaPlayer != null&&mMediaPlayer.isPlaying()) {mMediaPlayer.pause();isPause = true;}}/*** 播放*/public static void resume(){if (mMediaPlayer != null && isPause) {mMediaPlayer.start();isPause = false;}}/*** activity 被销毁  释放*/public static void release(){if (mMediaPlayer != null) {mMediaPlayer.release();mMediaPlayer = null;}}
}

listview 的Adapter:

/***list的adapter* Created by Administrator on 2017/11/28.*/public class RecorderAdapter extends ArrayAdapter<Recorder> {//item 最小最大值private int mMinItemWidth;private int mMaxIItemWidth;private LayoutInflater mInflater;public RecorderAdapter(@NonNull Context context, List<Recorder> datas) {super(context,-1, datas);mInflater = LayoutInflater.from(context);//获取屏幕宽度WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);//item 设定最小最大值mMaxIItemWidth = (int) (outMetrics.widthPixels * 0.7f);mMinItemWidth = (int) (outMetrics.widthPixels * 0.15f);}@NonNull@Overridepublic View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {convertView = mInflater.inflate(R.layout.item_recorder, parent, false);holder = new ViewHolder();holder.seconds = convertView.findViewById(R.id.id_recorder_time);holder.length = convertView.findViewById(R.id.id_recorder_length);convertView.setTag(holder);}else {holder = (ViewHolder) convertView.getTag();}//设置时间  matt.round 四舍五入holder.seconds.setText(Math.round(getItem(position).time)+"\"");//设置背景的宽度ViewGroup.LayoutParams lp = holder.length.getLayoutParams();//getItem(position).timelp.width = (int) (mMinItemWidth + (mMaxIItemWidth / 60f*getItem(position).time));return convertView;}private class ViewHolder{TextView seconds;View length;}
}

在string.xml中

    <string name="str_recorder_normal">按住说话</string><string name="str_recorder_recording">松开结束</string><string name="str_recorder_want_cancel">松开手指,取消发送</string>

在style.xml中

<style name="Theme_AudioDialog"><item name="android:windowBackground">@android:color/transparent</item><!--Dialog的windowFrame框为无--><item name="android:windowFrame">@null</item><!--是否浮现在activity之上--><item name="android:windowIsFloating">true</item><!--//是否半透明--><item name="android:windowIsTranslucent">true</item><!--/背景是否模糊显示--><item name="android:backgroundDimEnabled">true</item></style>

好了以上就是所有的代码了。

不懂得可以问我哦,或者自己查查百度吧。

我的注释已经很多了,理理逻辑,应该很好懂的。

源码地址:源码

图片资源:资源图片

Android 仿微信实现语音聊天功能相关推荐

  1. android 仿微信聊天界面 以及语音录制功能,Android仿微信录制语音功能

    本文实例为大家分享了Android仿微信录制语音的具体代码,供大家参考,具体内容如下 前言 我把录音分成了两部分 1.UI界面,弹窗读秒 2.一个类(包含开始.停止.创建文件名功能) 第一部分 由于6 ...

  2. android仿微信语音聊天功能,Android仿微信发送语音消息的功能及示例代码

    微信的发送语音是有一个向上取消的,我们使用ontouchlistener来监听手势,然后做出相应的操作就行了. 直接上代码: //语音操作对象 private mediaplayer mplayer ...

  3. android右滑返回动画,Android仿微信右滑返回功能的实例代码

    先上效果图,如下: 先分析一下功能的主要技术点,右滑即手势判断,当滑到一直距离时才执行返回,并且手指按下的位置是在屏幕的最左边(这个也是有一定范围的),  这些可以实现onTouchEvent来实现. ...

  4. Android 仿微信显示的聊天照片

    Android 仿微信显示的聊天照片 Android 仿微信显示的聊天照片,效果如下图所示: 这种显示的样式就是和微信的显示照片的样式是一样的,微信的实现我不知道是否和我一样,今天我来和大家介绍一下我 ...

  5. Android仿微信小视频录制功能(二)

    Android仿微信小视频录制功能(二) 接着上一篇,在完成了录制功能后,伟大的哲学家沃兹基索德曾经说过:"有录就有放.",那么紧接着就来实现播放功能,按照国际惯例,先上下效果图: ...

  6. Android仿微信发送语音消息动态提示,支持上滑取消发送

    Android仿微信发送语音消息动态提示,支持上滑取消发送 先来几张图说明一下,简单直接: 是不是看了图片就秒懂 了. 下面来分析代码实现,直接撸代码. 主页面 AudioSendActivity.j ...

  7. android+微信语音,android 仿微信按住语音说话(语音聊天)源码下载

    [实例简介] [实例截图] [核心代码] package com.example.weixin_record; import java.util.ArrayList; import java.util ...

  8. UI设计之【android 仿微信、QQ聊天,带表情,可翻页,带翻页拖动缓冲】

    转自: http://blog.csdn.net/lnb333666/article/details/8546497 如题,这是公司项目的一个功能模块,先上个效果图: 其次大致说说原理: 1,首先判断 ...

  9. Android UI【android 仿微信、QQ聊天,带表情,可翻页,带翻页拖动缓冲】

    如题,这是公司项目的一个功能模块,先上个效果图: 其次大致说说原理: 1,首先判断输入的字符,是否包含表情的文字,比如   这个表情对应的文件名为 emoji_1.png,它对应的文字描述 : [可爱 ...

  10. vue中使用微信jssdk语音聊天功能

    1.绑定域名 2.引入JS文件 前面两步不细说,直接看官方文档就行,官方文档 3.wx.config配置: 在这边要注意有一个坑必须要注意一下:可能会遇到安卓系统配置正常,ios上面报签名无效配置失败 ...

最新文章

  1. 转:SAP 零售业POS心得分享
  2. Activiti工作流的应用示例
  3. 成功解决当Win10系统进行深度学习的时候发现系统C盘满了,教你如何正确卸载一些非必要的内容
  4. 查看mysql进程--show processlist
  5. 应用深度学习使用 Tensorflow 对音频进行分类
  6. 关于如何在BCB中使用CodeGuard
  7. 关于Oracle与MySQL的使用总结
  8. access 导入txt 找不到可安装的isam_由浅入深:Python 中如何实现自动导入缺失的库?...
  9. 销售系统软件mysql_Max(TM)销售管理系统
  10. Android基础 --- Widget
  11. CCCC-GPLT L2-019. 悄悄关注 团体程序设计天梯赛
  12. Office - Excel如何查询重复值数量
  13. 常用的即时通讯软件排行榜TOP10介绍
  14. Java ClassLoader类加载机制(二)类加载器
  15. 和大家分享一款使用PHP+MYSQL搭建的OA办公管理系统源码
  16. 图文混排时,图片和文字垂直如何居中
  17. Couldnt check the working tree for unmerged files because of an error. bad signature index file cor
  18. 动态规划(Dynamic Programming)的一些事一些情
  19. RC6加密解密算法C#实现源码!
  20. 关于JDY23蓝牙模块调试

热门文章

  1. css最后一行省略号,CSS怎么实现单行、多行文本溢出显示省略号
  2. oracle创建数据库的先决条件,Oracle数据库安装先决条件检查失败解决方案
  3. 腾讯Bugly学习了解
  4. RAITE Hypervisor介绍
  5. vant swipe 三图一屏
  6. h5跳转到 苹果 ios app store 应用商店 的APP详情页面
  7. 微信向移动开放平台又迈进了一大步:微信开放平台更新
  8. Fault tolerant heap shim applied to current process. This is usually due to previous crashes
  9. 经纬度与墨卡托坐标转化
  10. 计算机内存与外存的区别及使用配合(内存外存区别与搭配;快速缓存;计算机总线结构;计算机程序内存分布(栈、堆、全局/静态、数据区、代码段))