安卓微信语音聊天 安卓微信语音通话
首先大家可以参考一下这个大神的例子,我写的也是在他的基础上改编的,多了数据库,下拉刷新加载数据,左右2种布局写入同一个ListView
一 数据库
有关数据库方面的知识,相信大家都不陌生,假如有不会的可以百度,或者参考我写的数据库方面的知识,很简洁:Android 数据库简单操作
/**
* 当MyDBHelper对象被创建时,该方法被调用,该方法主要是来作一些初始化的数据,比如建表操作
*/
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("sqlite", "***MyDBHelper's onCreate()....");
// 创建表
String createSQL = "create table come(id integer primary key,type int,time float not null,filePathString varchar(20) not null)";
db.execSQL(createSQL);
}
上面是建表语句,字段十分的简单,主要是主键id,通话时间以及路径。接下来就开始写有关对数据库的操作,主要是添加语音和查看。我们先看一下代码,下面的代码只要用于判断语音是否存储成功,成功返回true,否则为false:
/**
* 分页查询
*
* @param currentPage 当前页
* @param pageSize 每页显示的记录
* @return 当前页的记录
*/
public List<RecorderUtil> find(int currentPage, int pageSize) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
String sql = "select * from come limit ?,?";
Cursor cursor = db.rawQuery(sql, new String[] { String.valueOf(currentPage), String.valueOf(pageSize) });
while (cursor.moveToNext()) {
RecorderUtil sRecorderUtil = new RecorderUtil(1, cursor.getFloat(cursor.getColumnIndex("time")),
cursor.getString(cursor.getColumnIndex("filePathString")));
mDatas.add(sRecorderUtil);
}
return mDatas;
}
在接下来的开发中发现光依靠这个方法无法实现我们的目的,所以还需要知道语音的数量,我们看一下代码:
/**
* 查询记录的总数
* @return 当前页的数量
*/
public int getCount() {
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select count(*) from come", null);
cursor.moveToFirst();
int count = cursor.getInt(0);// 第0个下标参数
cursor.close();
return count;
}
有关数据库方面的代码其实就这么多,不需要把增删改查全部写完,只需要写出自己需要的部分。
二 下拉刷新功能:
使用下拉刷新,我用到的是PullToRefreshListView,这位大神已经很详细的讲解了如何使用PullToRefreshListView:
其实如果你不嫌麻烦,可以com.handmark.pulltorefresh.library路径下的所有代码全部导入你的项目中,也是可以使用的。
<com.handmark.pulltorefresh.library.PullToRefreshListView
xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:id="@+id/speak_list"
android:layout_width="match_parent"
android:layout_height="300dip"
android:drawSelectorOnTop="false"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:background="#ebebeb"
android:cacheColorHint="@android:color/transparent"
android:clipToPadding="false"
android:divider="@null"
android:dividerHeight="10dp"
android:paddingBottom="1dp"
android:transcriptMode="normal"
ptr:ptrMode="pullFromStart"
ptr:ptrOverScroll="false" />
这是引用代码,其实可以把他当做是一个ListView使用,那么我们首先希望在我们进入语音app的时候,是有数据的,而不是永远都是空的,这样就需要我们从数据库拉数据出来,
private ComeModle mComeModle ;
private int allRecorders = 0; //全部记录数
private List<RecorderUtil> mDatas = new ArrayList<RecorderUtil>();
try {
mComeModle= new ComeModle(MainActivity.this);
allRecorders=mComeModle.getCount();
mDatas=mComeModle.find((allRecorders-5),5);
Log.d(TAG, "mDatas count: " + mDatas.size());
mlistview.setAdapter(mAdapter);
} catch (Exception e) {
Log.i("exception", e.toString());
}
先定义一些参数,然后调用刚才调用刚才查询的方法,通过总数allRecorders,控制显示的位子,我们希望出现的最新的数据,而不是最上面id为一的数据,这是通过limit来实现的,limit的使用,文档有说明,中文的意思是
指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。
进去看到原有的数据还不够,我们该如何查看之前的数据呢?PullToRefreshListView本身就提供了下拉刷新的功能,我们需要做的是连一个接口实现他的方法,代码如下:
public class MainActivity extends Activity implements OnRefreshListener2<ListView> {
}
我们通过OnRefreshListener2<ListView>重写下拉刷新,代码如下:
/**
* @Description 下拉加载数据
* @param refreshView
*/
@Override
public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) {
// 获取消息
refreshView.postDelayed(new Runnable() {
@Override
public void run() {
if (mAdapter.getCount() > 0) {
mAdapter.clearItem();
}
try {
mComeModle= new ComeModle(MainActivity.this);
allRecorders=mComeModle.getCount();
//计算总页数
int pageSize=(allRecorders+5-1)/5;
if(MSG_ADD<=pageSize){
mDatas.addAll(0,mComeModle.find((allRecorders-5*(MSG_ADD++)),5));
}else {
Log.d(TAG, "jia zai wan cheng");
}
Log.d(TAG, String.valueOf(MSG_ADD));
Log.d(TAG, String.valueOf(pageSize));
Log.d(TAG, String.valueOf(mDatas.size()));
} catch (Exception e) {
Log.i("exception", e.toString());
}
mAdapter = new RecorderBaseAdapter(MainActivity.this, mDatas);
mlistview.setAdapter(mAdapter);
ListView mlist = mlistview.getRefreshableView();
if (!(mlist).isStackFromBottom()) {
mlist.setStackFromBottom(true);
}
mlist.setStackFromBottom(false);
refreshView.onRefreshComplete();
}
}, 200);
}
/**
* @Description 下拉加载数据
* @param refreshView
*/
@Override
public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {
}
首先我们计算了分页后的总页数,其中MSG_ADD是自增的,我定义了他的初始值为2,因为我希望得到的是倒数10个数据里面的前面5个数据,可能看着有些别扭,读者可以自己试一试,就明白其中的差距了,之后采用list.addAll()方法,希望可以将刚查到的数据累加到原来的List中,而且我们希望新增加的数据是在原来list的上面,而不是下面,所以最好使用list.addAll(0.mData);
其实很多时候我们需要控制ListView,让它显示最新的数据,但是PullToRefreshListView没有setSelection()这个方法,但其实还是可以实现的,需要转个弯,代码如下:
/**
* @Description 滑动到列表底部
*/
private void scrollToBottomListItem() {
ListView lv = mlistview.getRefreshableView();
if (lv != null) {
lv.setSelection(mAdapter.getCount() + 1);
}
}
通过上面的代码可以实现Listview显示在最底部,需要加在什么地方就看自己的需要了
三 自定义button按钮播放语音
这个自定义播放语音的botton是参考别人的,在文章的开头就已经提及,这里就不贴代码了,原作者播放语音的时候是有bug的,就是播放完语音之后,动画效果完成后会变成一个方块,这里做出改进。
/**
* 点击按钮语音发出
*/
button.setAudioFinishRecorderListener(new AudioFinishRecorderListener() {
@Override
public void onFinished(float seconds, String filePath) {
RecorderUtil recorder = new RecorderUtil(1, seconds, filePath);
mDatas.add(recorder);
mAdapter.notifyDataSetChanged();
scrollToBottomListItem();
if (new ComeModle(MainActivity.this).save(1, seconds, filePath)) {
// Toast.makeText(MainActivity.this, "save success!!!", Toast.LENGTH_SHORT).show();
Log.d(TAG, "save OK");
} else {
Log.d(TAG, "save Failed");
// Toast.makeText(MainActivity.this, "save failed!", Toast.LENGTH_SHORT).show();
}
}
});
mAdapter = new RecorderBaseAdapter(this, mDatas);
mlistview.setAdapter(mAdapter);
/**
* 列表点击播放
*/
mlistview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 播放动画
if (viewanim != null) {// 让第二个播放的时候第一个停止播放
viewanim.setBackgroundResource(R.drawable.adj);
viewanim = null;
}
viewanim = view.findViewById(R.id.id_recorder_anim);
viewanim.setBackgroundResource(R.drawable.play);
AnimationDrawable drawable = (AnimationDrawable) viewanim.getBackground();
drawable.start();
// 播放音频
MediaManager.playSound(mDatas.get(position - 1).filePathString, new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
viewanim.setBackgroundResource(R.drawable.adj);
}
});
}
});
思路是原作者给的,但我加了很多新的东西,其中RecoderUtil中我加了类型,用于实现后面一左一右的功能,数据库数据保存以及点击按钮语音播放之后会显示最新的语音数据,之后MediaManager中改变position的位子,不修改会造成数组越界,改变View中setBackgroundResourse()中的id值,这样播放动画效果后不会出现崩溃。
这个给一下有关播放MediaManager的源码:
package com.yeezone.cluster;
import java.io.IOException;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
/**
* @Description 播放语音
* @author xu.chen
* @datetime 2016/3/24
*/
public class MediaManager {
private static MediaPlayer mPlayer;
private static boolean isPause;
public static void playSound(String filePathString,
OnCompletionListener onCompletionListener) {
// TODO Auto-generated method stub
if (mPlayer==null) {
mPlayer=new MediaPlayer();
//保险起见,设置报错监听
mPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
mPlayer.reset();
return false;
}
});
}else {
mPlayer.reset();//就回复
}
try {
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setOnCompletionListener(onCompletionListener);
mPlayer.setDataSource(filePathString);
mPlayer.prepare();
mPlayer.start();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 停止函数
*/
public static void pause(){
if (mPlayer!=null&&mPlayer.isPlaying()) {
mPlayer.pause();
isPause=true;
}
}
/**
* 继续
*/
public static void resume()
{
if (mPlayer!=null&&isPause) {
mPlayer.start();
isPause=false;
}
}
public static void release()
{
if (mPlayer!=null) {
mPlayer.release();
mPlayer=null;
}
}
}
四 Listview界面
这边也可以参考我之前写的代码,网址
聊天LIstView
都知道时间越长,语音的长度也会越长,这里讲一下如何确定语音的长度
首先定义确定系统高度
// 获取系统宽度
WindowManager wManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wManager.getDefaultDisplay().getMetrics(outMetrics);
mMaxItemWith = (int) (outMetrics.widthPixels * 0.7f);
mMinItemWith = (int) (outMetrics.widthPixels * 0.15f);
之后返回界面的时候需要做一些处理,代码如下:
holder.seconds.setText(Math.round(mData.get(position).time) + "\"");
ViewGroup.LayoutParams lParams = holder.length.getLayoutParams();
lParams.width = (int) (mMinItemWith + mMaxItemWith / 60f * mData.get(position).time);
holder.length.setLayoutParams(lParams);
通过这样,就可以实现长度的*变化。
源码地址,说一下,Listview需要自己关联一下,上面有讲,不然会报错
下面为效果图
上一篇: WorkPlus 构建安全高效的内联网通信平台,促进企业内部协作
下一篇: 语言聊天社交解决方案