录音效果及Touch事件的分发

最近做一个项目,有类似于微信和按住录音,松开停止录音的效果,这些类似于录音的功能很容易做,但是由于自己的大意,那个触摸事件的触摸点的采集总是有问题,烦躁了好几天,今天总算将bug抓了出来,特以此文,祭奠那死去的bug.

一:录音功能的实现:

这个功能比较简单,直接贴出Code:

	/**
	 * 录音功能
	 */
	private void recordSound() {
		try {
			recorder = new MediaRecorder(); // 创建记录器对象
			recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频源, 麦克风
			recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_WB); // 设置输出格式, 3gp
			recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB); // 设置编码
			filePath = Environment.getExternalStorageDirectory() + "/"
					+ System.currentTimeMillis() + ".amr";
			recorder.setOutputFile(filePath); // 设置文件路径
			recorder.prepare(); // 准备
			Log.i(TAG, "开始录音。。。。。。。");
			//TODO:检测声音的大小
			recorder.start(); // 开始
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 停止录音的功能
	 */
	private void stopRecord() {
		if (recorder != null) {
			endTime = System.currentTimeMillis();
			Log.i(TAG, "停止录音endTime:" + endTime);
			recorder.stop();// 停止
			recorder.release();// 释放
			recorder = null;// 回收
		}
	}

二:音量动态变化的效果:

这里用到了PopupWindow及关键方法getMaxAmplitude的调用

PopupWindow的使用:

1.初始化popupWindow:

Code:

	/**
	 * 创建popupWindow
	 */
	private void createPopupWindow() {
		if(popupWindow != null)
			return;
		View view = View.inflate(getApplicationContext(), R.layout.popupwindow_record_sound, null);
		popupWindow = new PopupWindow(view);
		iv_rcd_hint_anim = (ImageView) view.findViewById(R.id.iv_rcd_hint_anim);
		popupWindow.setWidth(DensityUtil.dip2px(RecordSoundActivity.this, 150));
		popupWindow.setHeight(DensityUtil.dip2px(RecordSoundActivity.this, 200));
	}


2.显示popupWindow:

Code:

	/**
	 * 展示popupWindow
	 */
	private void showPopupWindow(){
		if(popupWindow.isShowing())
			return;
		int xoff = (rl_recordSound.getWidth()-popupWindow.getWidth())/2;
		int yoff = rl_recordSound.getHeight()+popupWindow.getHeight()-100;
		popupWindow.showAsDropDown(rl_recordSound, xoff , -yoff);
	}


3.隐藏popupWindow:

Code:

if (popupWindow.isShowing())
       popupWindow.dismiss();


效果图:

 

由于上面的图不是美丽的美工小美女做的,是从微信里面反编译出来的,有点丑,不过不打紧,目前功能第一,以后才是界面的事。

getMaxAmplitude的调用:

1.由于音量是在不断变化中的,所以getMaxAmplitude不是只执行一次,应该在一个线程中执行,要每隔一段时间采样一次,为了简单起见,用void java.util.Timer.schedule(TimerTask task, long delay, long period)

每隔200ms采样一次,然后将采集到的数据handler出去交给UI Thread处理以便让UI界面有动态变化的效果,这里需要注意的问题是:①当界面被另外一个界面覆盖后②:停止录音时 这两个情况都需要将录音那个对象回收掉:

  recorder.stop();// 停止

recorder.release();// 释放

recorder = null;// 回收

 

但在getMaxAmplitude是在线程中执行的,很可能就在recorder刚被回收后的那一刻,线程执行到了recorder.getMaxAmplitude();这个方法,会报空指针异常:NullPointerException,还有其他什么的乱七八糟的破玩意,所以捕获了一下异常的老子。

Code:

	new Timer().schedule(new TimerTask() {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				if(recorder != null){//下面要加锁!!!!
					synchronized (this) {
						int maxAmplitude = recorder.getMaxAmplitude();
						Log.i(TAG,"当前声音---音量:" + maxAmplitude);
						int index = maxAmplitude/200;
						if(index>6)
							index=6;
						Message msg = new Message();
						msg.what = GET_BG_INDEX;
						msg.obj = index;
						mHandler.sendMessage(msg);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				Log.i(TAG,"没有获取到音量");
			}
		}
	}, 0, 200);

改变主界面的handler的具体处理:


	private Handler mHandler = new Handler(){
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case GET_BG_INDEX:
				int index = (Integer) msg.obj;
				Log.i(TAG,"index:"+index);
				iv_rcd_hint_anim.setBackgroundResource(rcd_amin_bg[index]);
				break;
			}
		}
	};

三:Touch事件的处理:

这是关键的一步,老子就是在这一步被卡了几天,搞得欲仙欲死。其实一切代码逻辑都正常,关键老子为了屏幕适配加在布局文件中加了一个ScrollView,然后在自定义了一个RelativeLayout,然后写回调来处理触摸事件,结果Action_Move只能采样一小会,根本不能在你手指不规则移动时一直采样,这就令人非常蛋疼了,搞得我一直以为我Touch事件哪里出了问题,后来将ScrollView直接去掉,哗,整个世界清静了...

Code:


		rl_recordSound.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					createPopupWindow();
					iv_recordSound
							.setBackgroundResource(R.drawable.voice_after);
					showPopupWindow();
					recordSound();
					break;
				case MotionEvent.ACTION_MOVE:
					float getX = event.getX();
					float getY = event.getY();
					int left = rl_recordSound.getLeft();
					int right = rl_recordSound.getRight();
					int top = rl_recordSound.getTop();
					int bottom = rl_recordSound.getBottom();

					float r=(right-left)/2;//圆半径
					float ox=r+left;//圆心x坐标
					float oy=r+top;//圆心y坐标
					Double L=Math.pow(Math.abs((getX-150)), 2)+Math.pow(Math.abs((getY -150)), 2);
					L = Math.sqrt(L);
					
					if(L>r){
						if (popupWindow.isShowing())
							popupWindow.dismiss();
						iv_recordSound.setBackgroundResource(R.drawable.voice_before);
						stopRecord();
						toNextActivity();
						break;
					}
					break;
				case MotionEvent.ACTION_UP:
					iv_recordSound
							.setBackgroundResource(R.drawable.voice_before);
					if (popupWindow.isShowing())
						popupWindow.dismiss();
					stopRecord();
					toNextActivity();
					break;
				}
				return true;
			}
		});


布局没其他要讲的,只要没有被ScrollView等类似的玩意嵌套住就ok了,

遗留的问题:

①:这个界面的屏幕的适配<问题不严重>

②:ScrollView与其他View的嵌套使用问题

③:ScrollView的监听机制。







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值