使用线控耳机来操控应用功能
实现原理:通过广播拦截来实现。
(一)定义1个广播拦截器,用来拦截线控耳机按键产生的广播事件。
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
public class MediaButtonReceiver extends BroadcastReceiver {
/**
* Handler
*/
private Handler handler;
/**
* 构造器.
* @param handler
*/
public MediaButtonReceiver(Handler handler) {
this.handler = handler;
}
@Override
public void onReceive(Context context, Intent intent) {
boolean isActionMediaButton = Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction());
if(!isActionMediaButton) return;
KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if(event==null) return;
boolean isActionUp = (event.getAction()==KeyEvent.ACTION_UP);
if(!isActionUp) return;
int keyCode = event.getKeyCode();
long eventTime = event.getEventTime()-event.getDownTime();//按键按下到松开的时长
Message msg = Message.obtain();
msg.what = 100;
Bundle data = new Bundle();
data.putInt("key_code", keyCode);
data.putLong("event_time", eventTime);
msg.setData(data);
handler.sendMessage(msg);
//终止广播(不让别的程序收到此广播,免受干扰)
abortBroadcast();
}
}
(二)在主程序的处理:
(1)定义并注册广播服务
//初始化Handler对象 MyHandler handler = new MyHandler(); //初始化媒体(耳机)广播对象. MediaButtonReceiver mediaButtonReceiver = new MediaButtonReceiver(handler); //注册媒体(耳机)广播对象 IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON); intentFilter.setPriority(10000); registerReceiver(mediaButtonReceiver, intentFilter);
也可以这样注册广播:
<receiver android:name="MediaButtonReceiver"> <intent-filter android:priority="10000"> <action android:name="android.intent.action.MEDIA_BUTTON" /> </intent-filter> </receiver>
(2)定义MyHandler和处理广播发回的消息:
private class MyHandler extends Handler{
@Override
public void handleMessage(Message msg) {
int what = msg.what;
switch(what){
case 100://单击按键广播
Bundle data = msg.getData();
//按键值
int keyCode = data.getInt("key_code");
//按键时长
long eventTime = data.getLong("event_time");
//设置超过2000毫秒,就触发长按事件
boolean isLongPress = (eventTime>2000);
switch(keyCode){
case KeyEvent.KEYCODE_HEADSETHOOK://播放或暂停
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE://播放或暂停
playOrPause();
break;
//短按=播放下一首音乐,长按=当前音乐快进
case KeyEvent.KEYCODE_MEDIA_NEXT:
if(isLongPress){
fastNext(1);//自定义
}else{
playNext();//自定义
}
break;
//短按=播放上一首音乐,长按=当前音乐快退
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
if(isLongPress){
fastPrevious(1);//自定义
}else{
playPrevious();//自定义
}
break;
}
break;
default://其他消息-则扔回上层处理
super.handleMessage(msg);
}
}
}
(3)应用程序退出的时候,别忘了取消注册的广播拦截器。
unregisterReceiver(mediaButtonReceiver);
如果你曾经使用java IO编程,你会很快碰到这种情况,某个类在OutputStream上创建数据而你需要将它发送给某个需要从输入流读取数据的类。
你很快会被问道,“java中如何将OutputStream转换为InputStream?”
方法一:使用字节数组缓存数据
最简单的方法是用字节数组缓存数据。代码
ByteArrayOutputStream out = new ByteArrayOutputStream();
class1.putDataOnOutputStream(out);
class2.processDataFromInputStream(
new ByteArrayInputStream(out.toByteArray())
);
于是,OutputStream就被转换为InputStream了。
方法二:使用管道
第一种方法的问题是你必须有足够的内存缓存所有数据。你可以使用文件系统缓存更多数据,但无论如何可处理数据的大小还是受到限制。
解决方法是创建一个线程产生数据到PipedOutputStream。当前线程可从中读取数据。
PipedInputStream in = new PipedInputStream();
PipedOUtputStream out = new PipedOutputStream(in);
new Thread(
new Runnable(){
public void run(){
class1.putDataOnOutputStream(out);
}
}
).start();
class2.processDataFromInputStream(in);|||
方法三:使用循环缓存区
方法二中的两个管道流,实际上管理着一个隐藏的循环缓存区。使用一个显式的循环缓存区更易于理解。CircularBuffers 有如下优点
一个CircularBuffers类而不是两个管道类。
较于缓存所有数据和额外线程的方法更容易使用。
你可以更改缓存大小而不必受限于管道缓存区1K的固定缓存大小。
多线程情形:
CircularByteBuffer cbb = new CircularByteBuffer();
new Thread(
new Runnable(){
public void run(){
class1.putDataOnOutputStream(cbb.getOutputStream());
}
}
).start();
class2.processDataFromInputStream(cbb.getInputStream());
单线程情形
// buffer all data in a circular buffer of infinite size
CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
class1.putDataOnOutputStream(cbb.getOutputStream());
class2.processDataFromInputStream(cbb.getInputStream());
在Activity的onCreate函数中,加入如下代码: