首先大家可以参考一下这个大神的例子,我写的也是在他的基础上改编的,多了数据库,下拉刷新加载数据,左右2种布局写入同一个ListView
这是他的代码 :http://download.csdn.net/detail/u013982769/8680185
一 数据库
有关数据库方面的知识,相信大家都不陌生,假如有不会的可以百度,或者参考我写的数据库方面的知识,很简洁: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:http://blog.csdn.net/harvic880925/article/details/17680305
其实如果你不嫌麻烦,可以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关键字后面的部分。
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) { }
其实很多时候我们需要控制ListView,让它显示最新的数据,但是PullToRefreshListView没有setSelection()这个方法,但其实还是可以实现的,需要转个弯,代码如下:
/** * @Description 滑动到列表底部 */ private void scrollToBottomListItem() { ListView lv = mlistview.getRefreshableView(); if (lv != null) { lv.setSelection(mAdapter.getCount() + 1); } }
三 自定义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); } }); } });
这个给一下有关播放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界面
这边也可以参考我之前写的代码,网址
都知道时间越长,语音的长度也会越长,这里讲一下如何确定语音的长度
首先定义确定系统高度
// 获取系统宽度 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需要自己关联一下,上面有讲,不然会报错
http://download.csdn.net/detail/qq_31307919/9492124
下面为效果图