本学期学习了移动软件开发课程后,自己尝试实现了两个小功能,一个是利用OntouchListener()实现轨迹球滑动功能;一个是用Service实现一个简单播放器功能。
1.使用OnTouchListener()监听器实现一个轨迹球随着食指滑动运动;
2.我这边用了名字缩写代替轨迹球;
当按下手指的时候记录手指的坐标作为起始坐标,当手指抬起的时候把当前手指坐标与起始坐标对比,由此可以判断手指滑动的方向。
Android提供的基于事件监听接口有OnClickListener、OnLongClickListener、OnFocusChangeListener、OnKeyListener、OnTouchListener、OnCreateContextMenuListener等。
OnClickListener接口:该接口处理的是点击事件。在触摸模式下,是在某个View上按下并抬起的组合动作,而在键盘模式下,是某个View获得焦点后点击确定键或者按下轨迹球事件。
OnLongClickListener接口: OnLongClickListener接口与上述的OnClickListener接口原理基本相同,只是该接口为View长按事件的捕捉接口,即当长时间按下某个View时触发的事件。
OnFocusChangeListener接口:OnFocusChangeListener接口用来处理控件焦点发生改变的事件。如果注册了该接口,当某个控件失去焦点或者获得焦点时都会触发该接口中的回调方法。
OnKeyListener接口:是对手机键盘进行监听的接口,通过对某个View注册并监听,当View获得焦点并有键盘事件时,便会触发该接口中的回调方法。
OnTouchListener接口:是用来处理手机屏幕事件的监听接口,当为View的范围内触摸按下、抬起或滑动等动作时都会触发该事件。
OnCreateContextMenuListener接口:是用来处理上下文菜单显示事件的监听接口。该方法是定义和注册上下文菜单的另一种方式。
主要代码:
// An highlighted block
public class MainActivity extends AppCompatActivity {
private int screenW;
private int screenH;
public LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayout = (LinearLayout) findViewById(R.id.root);
linearLayout.addView(new MyView(this));
}
class MyView extends View {
private Paint paint;
private float cx = 50;
private float cy = 50;
public MyView(Context context) {
super(context);
initPaint();
}
private void initPaint(){
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setTextSize(40);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.drawText("cc",cx,cy,paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 按下
cx = (int) event.getX();
cy = (int) event.getY();
// 通知重绘
postInvalidate();
break;
case MotionEvent.ACTION_MOVE:
// 移动
cx = (int) event.getX();
cy = (int) event.getY();
// 通知重绘
postInvalidate();
break;
case MotionEvent.ACTION_UP:
// 抬起
cx = (int) event.getX();
cy = (int) event.getY();
// 通知重绘
postInvalidate();
break;
}
return true;
} }
}
布局文件:
在设置监听器利用匿名监听类public boolean onTouchEvent(MotionEvent event) 方法,进行监听的设置,其中监听Touch时,有一些动作需要注意,ACTION_DOWN,ACTION_MOVE,ACTION_UP分别指的是屏幕开始触摸,滑动,离开屏幕动作,设置完以后,尤其要注意返回值的作用,具体情况如下:
1.如果返回值为true,那么系统会连续处理触摸事件,处理完一个触摸事件以后,不会执行结束,而是准备执行下一次操作。
2.如果返回值为flase,那么系统只会处理触摸事件一次,处理完后,就以结束为准,不会再触发事件的处理。
1.播放器具有开始/暂停,跳转到下/上一首歌功能。实现通过一个Activity远程绑定和打开该Service。
2.加入拖拽进度条功能,通过拖拽控制播放进度。
Service是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
菜鸟教程中有更为详细的介绍及具体操作例子,菜鸟链接:
Android :Service.
Service基类定义了不同的回调方法,这边只介绍几种:
方法 | 描述 |
---|---|
onBind | 当其他组件想要通过bindService()来绑定服务时,系统调用该方法。如果你实现该方法,你需要返回IBinder对象来提供一个接口,以便客户来与服务通信。你必须实现该方法,如果你不允许绑定,则直接返回null。 |
onCreate() | 当服务通过onStartCommand()和onBind()被第一次创建的时候,系统调用该方法。该调用要求执行一次性安装。 |
MainActivity:
public class MainActivity extends Activity implements View.OnClickListener {
SeekBar seekBar;
TextView curTime,totalTime;
TextView title;
private ServiceConnection sc;
private MusicService ms;
private boolean isStop;
private double totalTimeInt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter(MusicService.MFILTER);
registerReceiver(new MusicReceiver(),filter);
sc = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
ms = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
ms = ((MusicService.MBinder)service).getService();//1
}
};
Button previous = (Button) findViewById(R.id.previous);
Button next = (Button) findViewById(R.id.next);
Button stop = (Button) findViewById(R.id.stop);
Button stopService = (Button) findViewById(R.id.stopService);
seekBar = (SeekBar) findViewById(R.id.mSeekbar);
curTime = (TextView) findViewById(R.id.curTime);
totalTime = (TextView) findViewById(R.id.totalTime);
title = (TextView) findViewById(R.id.title);
previous.setOnClickListener(this);
next.setOnClickListener(this);
stop.setOnClickListener(this);
stopService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.previous:
ms.playPrevious();
break;
case R.id.next:
ms.playNext();
break;
case R.id.stop:
if (isStop) {
ms.restart();
}
else {
ms.parse();
}
isStop = !isStop;
break;
case R.id.stopService:
Intent intent = new Intent(MainActivity.this,MusicService.class);
unbindService(sc);
stopService(intent);
break;
default:
break;
}
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Intent intent = new Intent(MainActivity.this,MusicService.class);
intent.setPackage(getPackageName());
bindService(intent,sc, Context.BIND_AUTO_CREATE);
//startService(intent);
}
private String transferMilliToTime(int millis){
DateFormat format = new SimpleDateFormat("mm:ss");
String result = format.format(new Date(millis));
return result;
}
private class MusicReceiver extends BroadcastReceiver {//3
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getIntExtra(MusicService.CURTIME,0)!=0) {
double curTimeInt = intent.getIntExtra(MusicService.CURTIME,0);
curTime.setText(transferMilliToTime((int)curTimeInt));
double result = curTimeInt/totalTimeInt*100;
seekBar.setProgress((int) Math.floor(result));
}
else if(intent.getIntExtra(MusicService.TOTALTIME,0)!=0) {
totalTimeInt = intent.getIntExtra(MusicService.TOTALTIME,0);
totalTime.setText(transferMilliToTime((int)(totalTimeInt)));
}
else if (!TextUtils.isEmpty(intent.getStringExtra(MusicService.NAME))) {
title.setText(intent.getStringExtra(MusicService.NAME));
}
}
}
}
MainService:
public class MusicService extends Service {
private List musicList;
private MediaPlayer player;
private int curPage;
public static final String MFILTER = "broadcast.intent.action.text";
public static final String NAME = "name";
public static final String TOTALTIME = "totaltime";
public static final String CURTIME = "curtime";
@Override
public IBinder onBind(Intent intent) {//1
// TODO Auto-generated method stub
return (IBinder) new MBinder();
}
public class MBinder extends Binder {//2
public MusicService getService(){
return MusicService.this;
}
public MediaPlayer getPlayer(){
return player;
}
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
musicList = new ArrayList();
fillMusicList(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC));
player = new MediaPlayer();
if (musicList.size() != 0) {
startPlay();
}
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
player.reset();
curPage = curPage==musicList.size()-1? (curPage+1)%musicList.size() : curPage+1;
startPlay();
}
});
}
/*迭代获取 音乐 文件*/
private void fillMusicList(File dir){
File[] sourceFiles = dir.listFiles();
for(File file : sourceFiles){
if (file.isFile() && file.getName().endsWith(".mp3"))
musicList.add(file);
else if (file.isDirectory())
fillMusicList(file);
}
}
private void startPlay(){
if(musicList.size()!=0) {
mSendBroadCast(NAME, musicList.get(curPage).getName());//4
try {
player.setDataSource(musicList.get(curPage).getAbsolutePath());
player.prepare();
player.start();
player.getDuration();
mSendBroadCast(TOTALTIME, player.getDuration());
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
mSendBroadCast(CURTIME, player.getCurrentPosition());
}
}, 0, 1000);
} 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 void playNext(){
curPage = curPage==musicList.size()-1? (curPage+1)%musicList.size() : curPage+1;
Log.d("curpage",String.valueOf(curPage));
player.reset();
startPlay();
}
public void playPrevious(){
curPage = curPage==0? 0 : curPage-1;
Log.d("curpage",String.valueOf(curPage));
player.reset();
startPlay();
}
public void parse(){
player.pause();
}
public void restart(){
player.start();
}
private void mSendBroadCast(String key, String value){
Intent intent = new Intent(MFILTER);
intent.putExtra(key,value);
sendBroadcast(intent);
}
private void mSendBroadCast(String key, int value){
Intent intent = new Intent(MFILTER);
intent.putExtra(key,value);
sendBroadcast(intent);
}
}
布局文件:
作者:石超超
参考链接: https://blog.csdn.net/qq_41939302/article/details/84719033.
原文地址: https://blog.csdn.net/ccbuhuidaima/article/details/106651239.