Handler && Timer(音乐播放器)
来源:互联网 发布:去外企工作好吗 知乎 编辑:程序博客网 时间:2024/06/03 21:14
研究这两个的区别好久了,一个定时器用Handler做出来了,但是用timer怎么都做不出来,现在终于明白了,好开心。
这是我学到的一句话:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。
在我们Android开发过程中,经常需要执行一些短周期的定时任务,这时候有两个选择Timer或者Handler。然而个人认为:Handler在多个方面比Timer更为优秀,更推荐使用。
- 可重复执行
Handler可以重复执行某个任务。
Timer若在某个任务执行/取消之后,再次执行则会抛出一个IllegalStateException异常。为了避免这个异常,需要重新创建一个Timer对象。
- UI界面更新
Handler:在创建的时候可以指定所在的线程,一般在Activity中构建的,即主线程上,所以可以在回调方法中很方便的更新界面。
Timer:异步回调,所以必须借助Handler去更新界面,不方便。
既然都得用Handler去更新界面了,为何不如把定时的功能也交给Handler去做呢?
这是实现音乐播放器的功能,随着音乐的播放,自动更新时间。
- Timer实现
package com.mingrisoft;import java.io.File;import java.io.IOException;import java.util.Timer;import java.util.TimerTask;import android.app.Activity;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;import android.widget.TextView;public class MainActivity extends Activity implements OnSeekBarChangeListener { private MediaPlayer player = new MediaPlayer(); // MediaPlayer对象 private boolean isPause = false; // 是否暂停 private File file; // 要播放的音频文件 private TextView hint; // 声明显示提示信息的文本框 private SeekBar sbar; private Timer timer, timer2; private TimerTask task, task2; private int position; private TextView mTextView_one, mTextView_two; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); sbar = (SeekBar) findViewById(R.id.sbar); final Button button1 = (Button) findViewById(R.id.button1); // 获取播放按钮 final Button button2 = (Button) findViewById(R.id.button2); // 获取“暂停/继续”按钮 final Button button3 = (Button) findViewById(R.id.button3); // 获取“停止”按钮 mTextView_one = (TextView) findViewById(R.id.main_textview_time_one); mTextView_two = (TextView) findViewById(R.id.main_textview_time_two); file = new File("/mnt/sdcard/Gary Allan - One More Time.mp3"); // 获取要播放的文件 sbar.setOnSeekBarChangeListener(this); // 初始化计时器 timer = new Timer(); task = new TimerTask() { @Override public void run() { if (player != null && player.isPlaying()) { final int progress = player.getCurrentPosition(); int total = player.getDuration(); sbar.setMax(total); sbar.setProgress(progress); //修改界面的相关设置只能在UI线程中执行 runOnUiThread(new Runnable() { @Override public void run() { String time = formatTime(progress); mTextView_one.setText(time); } }); } } }; timer.schedule(task, 1000, 1000); // 为MediaPlayer对象添加完成事件监听器 player.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { play(); // 重新开始播放 } }); // 为“播放”按钮添加单击事件监听器 button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { play();// 开始播放音乐 if (isPause) { button2.setText("暂停"); isPause = false; // 设置暂停标记变量的值为false } button2.setEnabled(true); // “暂停/继续”按钮可用 button3.setEnabled(true); // “停止”按钮可用 button1.setEnabled(false); // “播放”按钮不可用 } }); // 为“暂停/继续”按钮添加单击事件监听器 button2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (player.isPlaying() && !isPause) { player.pause(); // 暂停播放; isPause = true; ((Button) v).setText("继续"); button1.setEnabled(true); // “播放”按钮可用 } else { player.start(); // 继续播放 ((Button) v).setText("暂停"); isPause = false; button1.setEnabled(false); // “播放”按钮不可用 } } }); // 为“停止”按钮添加单击事件监听器 button3.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { player.stop(); // 停止播放; button2.setEnabled(false); // “暂停/继续”按钮不可用 button3.setEnabled(false); // “停止”按钮不可用 button1.setEnabled(true); // “播放”按钮可用 } }); } // 播放音乐的方法 private void play() { try { player.reset(); player.setDataSource(file.getAbsolutePath()); // 重新设置要播放的音频 player.prepare(); // 预加载音频 player.start(); // 开始播放 int position = player.getDuration(); mTextView_two.setText(formatTime(position)); } catch (Exception e) { e.printStackTrace(); // 输出异常信息 } } @Override protected void onDestroy() { if (player.isPlaying()) { player.stop(); // 停止音频的播放 } player.release(); // 释放资源 timer.cancel(); task.cancel(); timer = null; task = null; super.onDestroy(); } @Override public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { // TODO Auto-generated method stub } @Override public void onStartTrackingTouch(SeekBar arg0) { // TODO Auto-generated method stub } @Override public void onStopTrackingTouch(SeekBar arg0) { // TODO Auto-generated method stub int position = sbar.getProgress(); if (player != null && player.isPlaying()) { player.seekTo(position); } } private static String formatTime(int time) { if (time / 1000 % 60 < 10) { return time / 1000 / 60 + ":0" + time / 1000 % 60; } else { return time / 1000 / 60 + ":" + time / 1000 % 60; } }}
- Handler实现
package com.example.mymusic;import java.io.File;import android.annotation.SuppressLint;import android.app.Activity;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;import android.widget.TextView;public class Main extends Activity implements OnClickListener { MediaPlayer mMediaPlayer; Button mPlayButton, mPauseButton, mStopButton, mForWard, mBackWard; SeekBar mSeekBar; TextView mTextView_one, mTextView_two; Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { if (mMediaPlayer != null) { int currentPosition = mMediaPlayer.getCurrentPosition(); mSeekBar.setProgress(currentPosition); String time = formatTime(currentPosition); mTextView_one.setText(time); mHandler.sendEmptyMessageDelayed(0, 1000); } }; }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initView(); setPlayListener(); setPause(); setStopListener(); setSeekBarListener(); } /******************************************************** * 初始化控件 */ private void initView() { mPlayButton = (Button) findViewById(R.id.button1); mPauseButton = (Button) findViewById(R.id.button2); mStopButton = (Button) findViewById(R.id.button3); mForWard = (Button) findViewById(R.id.media_forward); mBackWard = (Button) findViewById(R.id.media_backwrad); mSeekBar = (SeekBar) findViewById(R.id.seekBar); mTextView_one = (TextView) findViewById(R.id.main_textview_time_one); mTextView_two = (TextView) findViewById(R.id.main_textview_time_two); mForWard.setOnClickListener(this); mBackWard.setOnClickListener(this); } /******************************************************* * 必须在方法中初始化mMediaPlayer对象 播放音乐的初始化动作 setDataSource(path)设置音频的路径就是mp3的路径 * mMediaPlayer.prepare()此方法就是装载音频文件 * mMediaPlayer.start();此方法必须在上面的方法执行完毕后才可以 * * @param path * 传入音频文件的路径参数 */ public void play(String path) { if (mMediaPlayer == null) { try { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(path); mMediaPlayer.prepare(); mMediaPlayer.start(); int position = mMediaPlayer.getDuration(); mTextView_two.setText(formatTime(position)); mSeekBar.setMax(position); mHandler.sendEmptyMessageDelayed(0, 1000); } catch (Exception e) { e.printStackTrace(); } } else if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) { mMediaPlayer.start(); } } /********************************************************** * 设置播放按钮的点击事件 同时执行播放音乐方法 此点击事件采用的是匿名内部类的方式实现的 */ public void setPlayListener() { mPlayButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { play("/mnt/sdcard/a.mp3"); } }); } /********************************************************* * 暂停当前播放的音乐 */ @SuppressLint("SdCardPath") public void setPause() { mPauseButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); } } }); /* * if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { * mMediaPlayer.pause(); } */ } /************************************************* * 设置点击暂停按钮的点击事件 同时执行mMediaPlayer的暂停pause方法 * 此点击事件的方式是采用xml属性中设置onclick这个属性的方法 */ public void pause(View v) { setPause(); } /************************************************ * 停止播放音乐的方法 同时我们要释放内存,节约内存 把mMediaPlayer赋值为空,返回到开始播放的状态 */ public void stop() { if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; } } /************************************************* * 设置停止按钮的监听事件 此按钮的监听事件采用第三种方式 */ public void setStopListener() { mStopButton.setOnClickListener(listener); } OnClickListener listener = new OnClickListener() { @Override public void onClick(View v) { stop(); } }; /*************************************************** * 设置快进10秒方法 */ public void forWard() { if (mMediaPlayer != null) { int position = mMediaPlayer.getCurrentPosition(); mMediaPlayer.seekTo(position + 10000); } } /***************************************************** * 设置后退10秒的方法 */ public void backWard() { if (mMediaPlayer != null) { int position = mMediaPlayer.getCurrentPosition(); if (position > 10000) { position -= 10000; } else { position = 0; } mMediaPlayer.seekTo(position); } } /******************************************************** * 设置seekbar的拖动监听事件 */ public void setSeekBarListener() { mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { public void onStopTrackingTouch(SeekBar seekBar) { } public void onStartTrackingTouch(SeekBar seekBar) { } public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub if (mMediaPlayer != null && fromUser) { mMediaPlayer.seekTo(progress); } } }); } /******************************************************* * 关闭当前页面,停止播放 */ @Override protected void onDestroy() { super.onDestroy(); stop(); } /******************************************************** * 设置快进和后退按钮的监听事件 * * @param v */ @Override public void onClick(View v) { switch (v.getId()) { case R.id.media_forward: forWard(); break; case R.id.media_backwrad: backWard(); break; default: break; } } /******************************************************** * 对时间的格式化 * * @param time * @return */ public static String formatTime(int time) { if (time / 1000 % 60 < 10) { return time / 1000 / 60 + ":0" + time / 1000 % 60; } else { return time / 1000 / 60 + ":" + time / 1000 % 60; } }}
总结:
主线程不更新UI,在Timer的例子里面,UI的改变是在主线程里面,所以会有线程安全问题,我想把它单独出来,水平有限,而且代码比较粗糙,不建议使用。
下面是二者安全使用的对比:
http://blog.csdn.net/dany1202/article/details/6129548
阅读全文
0 0
- Handler && Timer(音乐播放器)
- 用SurfaceView,Timer以及Handler实现的一个带有音乐和文字的电子相册,可以自动播放~
- android音乐播放器播放音乐卡
- Android 音乐播放 类似音乐播放器
- J2ME中TimerTask与Timer类定时播放音乐
- flash音乐播放器
- 常见音乐播放器
- WEB音乐播放器
- Google 音乐播放器
- 单片机音乐播放器
- 简易音乐播放器
- 网页音乐播放器
- 音乐定时播放器
- android 音乐播放器
- 音乐播放器代码
- 音乐播放器01
- 个人音乐播放器
- YOYOPlayer音乐播放器
- matlab——NN代码(nnsetup)解析
- 20171202:方法和数组的学习
- 伪码农的日志_12.2_软件工程过程模型
- idea15更改项目的jdk版本
- latex中同一处引用多篇文献
- Handler && Timer(音乐播放器)
- 不同版本Hidernate获得SessionFactory对象的方法
- 链表在某位置插入某数
- 【转载】CFD新手应当了解的一些事情
- Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(六)将接口用 webpack 代理到本地
- Android学习记录
- SpringMVC 启动doDispatch类解析
- C语言小知识(1)
- Mybatis中$和#的区别