工作忙学习忙,天天都是忙啊。今天要记录的是一个仿QQ的音乐播放器,时间有限,功能不是很齐全,但基本雏形和功能都已完成。作为一个中期的过度。下次再开始真正的大项目。
音乐播放器,基本上算是android程序员都做过的一个练习项目了。不是很难,但想做的很漂亮,很完美,也不是那么容易的。本文拿它来讲,一方面是典型,把android四大组件都用上了,还用到各种布局,以及Notification和Toast等等信息提示类的内容。让我们开始吧,每天进步一点点!本文采用原型模型进行讲解。
原型模型又称快速原型,主要是为了应对需求模糊的项目。百度百科这样说:快速原型模型需要迅速建造一个可以运行的软件原型 ,以便理解和澄清问题,使开发人员与用户达成共识,最终在确定的客户需求基础上开发客户满意的软件产品。
一、快速分析
一个音乐播放器的基本需求就是对音乐的播放控制,音乐内容的展示,还有音乐的选择。
在此基础上,可以加入,网络音乐资源,定时关闭,摇一摇切歌,音乐锁屏等等提高用户体验的功能。
功能需求:
播放控制:播放 暂停 上一曲 下一曲 滑动快进 及 通知栏控制等
内容展示:歌名 歌手 时间 歌词 专辑等
音乐选择:音乐列表等
二、构造原型
本程序仿QQ音乐播放器:原型包括以下activity(欢迎界面 音乐列表界面 音乐播放界面) 以及后台播放服务(音乐播放服务) 和通知栏控制通知的设计和实现。
知识点预研:
1、动画详解
Android的动画主要包括三种:Tween Animation、Frame Animation Property Animation。
Tween Animation也是最常见的动画效果。主要有Alpha Scale Rotate Translate四种,实现方式可以使用java代码:AnimationSet和相应的AlphaAnimation ScaleAnimation RotateAnimation TranslateAnimation类;也可以使用xml文件实现:set rotate translate alpha scale标签实现。
本项目中的使用实例:
// 旋转动画
RotateAnimation rotate = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(DELAY);
// 渐变动画
AlphaAnimation alpha = new AlphaAnimation(0.1f, 1.0f);
alpha.setDuration(DELAY);
image_splash.startAnimation(rotate);
wordsa_splash.startAnimation(alpha);
wordsb_splash.startAnimation(alpha);
关于动画可参考:
http://blog.csdn.net/huxueyan521/article/details/8179036
http://blog.csdn.net/actual_/article/details/6943556
http://blog.csdn.net/lmj623565791/article/details/38067475
http://blog.csdn.net/banketree/article/details/25773243
2、布局详解
Android系统主要包括五大布局:LinearLayout RelativeLayout FrameLayout AbsoluteLayout TableLayout; 最常用的是前三个, 第四个现在已经废弃;它们之前的继承关系如图:
具体可参考:
http://blog.csdn.net/xujinsmile/article/details/8393647
http://blog.csdn.net/qinlicang/article/details/6091807
3、四大组件
这个大家太熟悉了。Activity Service ContentProvider BroadcastReceiver。别人已经讲解的很详细了,我就不再赘述了。请参考:
http://www.cnblogs.com/pepcod/archive/2013/02/11/2937403.html
http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html
4、ListView
这个是必须要好好掌握的一个控件。这是新手向老手进化的一个小标志。在iOS开发中,UITableView和这个控件的功能相似,其在iOS中占据非常非常重要的作用,一般的iOS书中都会发一大章节去讲解。所以在android里,一定要掌握这个控件。
在android里,其实它很简单,主要有两个重点,一个是控件本身,另一个是Adapter。
实现ListView常用两种Adapter 一个是SimpleAdapter;另一个是extends BaseAdapter。推荐后者。
可参考:
http://blog.csdn.net/xiazdong/article/details/7536115
http://blog.csdn.net/ygc87/article/details/7389603
http://blog.csdn.net/tianfeng701/article/details/7557819
5、MediaPlayer
这个是音乐播放的核心。但也是最简单实用的,但其原理却很复杂。实现方法请参考下面的代码。原理附图一张:
具体请参考:
http://blog.csdn.net/murongshusheng/article/details/7580689
http://blog.csdn.net/eustoma/article/details/6706492
http://blog.csdn.net/cankingapp/article/details/7972725
6、信息提示
信息提示主要包括:Notification Toast Dialog请参考
http://blog.csdn.net/qwm8777411/article/details/45585603
由于时间篇幅和能力的问题,我没有作详细讲解,非常抱歉。但,所有内容,如果大家有所疑问,我一定尽我所能为大家讲解。还是那句话重要的是学习能力。
一点小经验:我搜索时是这样的:比如我想学习一下activity,我会这样搜索:android activity详解;如果是我想知道StringBuilder类 我会这样:java StringBuilder
有时我也会用google的高级搜索。大家可以百度google hacking学习一下google的高级搜索,此搜索同样可以用在百度里。
希望对您有所帮助。谢谢。
程序包结构:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- 第一版 对于一个真正实用的产品 版本非常重要 -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.leo.lovemusic"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="21" />
<!-- 需要从本地读取歌曲 所以需要SD卡的读权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 自定义自己的Application通过android:name指定 -->
<application
android:name="com.leo.lovemusic.AppContext"
android:allowBackup="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.NoActionBar.TranslucentDecor" >
<!-- 欢迎界面Splash -->
<activity
android:name=".SplashActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 播放音乐Activity -->
<activity android:name="com.leo.lovemusic.activity.PlayActivity" />
<!-- 音乐列表Activity -->
<activity android:name="com.leo.lovemusic.activity.MusicActivity" />
<!-- 后台音乐服务 -->
<service android:name="com.leo.lovemusic.service.PlayService" />
</application>
</manifest>
SplashActivity.java
package com.leo.lovemusic;
import com.leo.lovemusic.activity.MusicActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
/**
* @time 2015-09-14
* @author Leo
* @describe 欢迎界面 logo 理念 动画等
*
*/
public class SplashActivity extends Activity {
private static final String TAG = SplashActivity.class.getSimpleName();
private static final int DELAY = 1500;// 动画时间
private ImageView image_splash = null;// 要展示的图片
private TextView wordsa_splash = null;// 要展示的内容
private TextView wordsb_splash = null;// 要展示的内容
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
init();// 初始化数据
}
/**
* 初始化数据
*/
private void init() {
findViewsByIds();
setAnimation();
}
/**
* 得到控件
*/
private void findViewsByIds() {
image_splash = (ImageView) findViewById(R.id.iv_image_splash);
wordsa_splash = (TextView) findViewById(R.id.tv_wordsa_splash);
wordsb_splash = (TextView) findViewById(R.id.tv_wordsb_splash);
}
/**
* 设置动画效果
*/
private void setAnimation() {
// 旋转动画
RotateAnimation rotate = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
rotate.setDuration(DELAY);
// 渐变动画
AlphaAnimation alpha = new AlphaAnimation(0.1f, 1.0f);
alpha.setDuration(DELAY);
image_splash.startAnimation(rotate);
wordsa_splash.startAnimation(alpha);
wordsb_splash.startAnimation(alpha);
// 动画监听
rotate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub
Log.d(TAG, "animation start");
}
@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
Log.d(TAG, "animation repeat");
}
@Override
public void onAnimationEnd(Animation arg0) {
// TODO Auto-generated method stub
Log.d(TAG, "animation end");
Intent intent = new Intent(SplashActivity.this,
MusicActivity.class);
startActivity(intent);
finish();
}
});
}
}
PlayService.java
package com.leo.lovemusic.service;
import java.io.IOException;
import java.util.ArrayList;
import com.leo.lovemusic.R;
import com.leo.lovemusic.activity.PlayActivity;
import com.leo.lovemusic.bean.Music;
import com.leo.lovemusic.util.Constant;
import com.leo.lovemusic.util.Tool;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.widget.RemoteViews;
import android.widget.Toast;
/**
* 音乐播放的核心服务 有广播接收器,用于接收事件 有通知Notification
*
* @author Leo time:2015-05-01
*/
@SuppressLint("HandlerLeak")
public class PlayService extends Service {
public ArrayList<Music> musics = null;// 所有音乐信息
public int current_position = 0;// 当前播放位置
private MediaPlayer mMediaPlayer = null;// 音乐播放类
private SharedPreferences sp = null;// 得到及存储播放位置
private boolean isFirstTime = true;// 第一次播放
private boolean isPlaying = false;// 是否正在播放
private int play_mode = 0;// 播放模式 目录0 单曲1 随机2
private NotificationManager mNotificationManager = null;// 通知管理器
private Notification notification = null;// 通知
private static final int ID = 111;// 通知ID
private static PlayService myself = null;// 我自己
private Handler mHandler = null;// 处理数据
private static final int DELAY = 1000;// delay
/**
* 获取Service实例来取得音乐信息和当前位置
*
* @return
*/
public static PlayService getMyself() {
return myself;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
myself = this;
initData();// 初始化数据
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
// super.handleMessage(msg);
if (msg.what == Constant.WHAT_EMPTY) {
if (mMediaPlayer != null) {
Intent intent = new Intent(Constant.ACTION_CURRENT_TIME);
intent.putExtra(Constant.KEY_CURRENT_TIME,
mMediaPlayer.getCurrentPosition());
sendBroadcast(intent);
}
}
}
};
}
/**
* @time 2015-09-14
* @author Leo
* @describe 定时更新seekbar显示音乐当前时间
*
*/
private class DelayThread extends Thread {
public void run() {
while (isPlaying) {
try {
mHandler.sendEmptyMessage(Constant.WHAT_EMPTY);
Thread.sleep(DELAY);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 获取播放模式 单曲 随机 还是顺序
*
* @return
*/
private int getPlayMode() {
int mode = sp.getInt(Constant.KEY_PLAY_MODE, 0);
return mode;
}
/**
* 用SharedPreference保存当前播放模式 用于退出时用 下次开启时获取
*/
private void setPlayMode() {
Editor editor = sp.edit();
editor.putInt(Constant.KEY_PLAY_MODE, play_mode);
editor.commit();
}
/**
* 得到上次播放到哪一首歌曲
*
* @return
*/
private int getPosition() {
int position = sp.getInt(Constant.KEY_POSITION, 0);
return position;
}
/**
* 存储歌曲播放位置
*/
private void setPosition() {
Editor editor = sp.edit();
editor.putInt(Constant.KEY_POSITION, current_position);
editor.commit();
}
/**
* 初始化通知
*/
@SuppressWarnings("deprecation")
private void initNotification() {
// 取得通知管理器
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// 实例通知
notification = new Notification(R.drawable.icon, "爱你音乐",
System.currentTimeMillis());
// 通过RemoteViews来取得自定义布局
RemoteViews contentView = new RemoteViews(getPackageName(),
R.layout.notification);
// 为上一曲绑定通知事件
Intent lastIntent = new Intent(Constant.ACTION_LAST);
PendingIntent last = PendingIntent.getBroadcast(this, 0, lastIntent, 0);
contentView.setOnClickPendingIntent(R.id.iv_last_notification, last);
// 为下一曲绑定通知事件
Intent nextIntent = new Intent(Constant.ACTION_NEXT);
PendingIntent next = PendingIntent.getBroadcast(this, 0, nextIntent, 0);
contentView.setOnClickPendingIntent(R.id.iv_next_notification, next);
// 为播放和暂停绑定通知事件
Intent controlIntent = new Intent(Constant.ACTION_CONTROL);
PendingIntent control = PendingIntent.getBroadcast(this, 0,
controlIntent, 0);
contentView.setOnClickPendingIntent(R.id.iv_control_notification,
control);
// 为整个通知绑定单击事件
Intent notificationIntent = new Intent(PlayService.this,
PlayActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(
PlayService.this, 0, notificationIntent, 0);
// 为notification设置自定义布局和事件
notification.contentView = contentView;
notification.contentIntent = contentIntent;
// 设置通知不 可清除且为紧急
notification.flags = Notification.FLAG_NO_CLEAR;
notification.flags = Notification.FLAG_INSISTENT;
// 启动通知
mNotificationManager.notify(ID, notification);
}
/**
* 显示通知
*
* @param bitmap
* @param title
* @param artist
*/
private void showNotification(Bitmap bitmap, String title, String artist) {
// 更新缩略图
if (bitmap != null) {
notification.contentView.setImageViewBitmap(
R.id.iv_image_notification, bitmap);
}
// 更新歌曲名
if (title != null) {
notification.contentView.setTextViewText(
R.id.tv_title_notification, title);
}
// 更新歌手名
if (artist != null) {
notification.contentView.setTextViewText(
R.id.tv_artist_notification, artist);
}
mNotificationManager.notify(ID, notification);
}
private void closeNotification() {
mNotificationManager.cancel(ID);
}
private void registerTheReceiver() {
// 注册广播接收器
IntentFilter filter = new IntentFilter();
filter.addAction(Constant.ACTION_LAST);
filter.addAction(Constant.ACTION_NEXT);
filter.addAction(Constant.ACTION_CONTROL);
filter.addAction(Constant.ACTION_CLOSE_NOTIFICATION);
filter.addAction(Constant.ACTION_PLAY_MODE);
filter.addAction(Constant.ACTION_SEEK_TO);
filter.setPriority(Integer.MAX_VALUE);
registerReceiver(mReceiver, filter);
}
/**
* 提示
*
* @param text
*/
private void toast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
/**
* 初始化数据
*/
private void initData() {
musics = Tool.findMusic(this);
if ((musics == null) || musics.size() <= 0) {
toast("非常抱歉,没有音乐");
return;
}
sp = getSharedPreferences(Constant.SP_NAME, Context.MODE_PRIVATE);
current_position = getPosition();
play_mode = getPlayMode();
registerTheReceiver();
// 实例化MediaPlayer
mMediaPlayer = new MediaPlayer();
// 绑定歌曲完成事件
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
// TODO Auto-generated method stub
if (play_mode == 0) {
nextMusic();
} else if (play_mode == 1) {
playMusic(current_position);
} else if (play_mode == 2) {
current_position = Tool.getRandomPosition(musics.size());
playMusic(current_position);
}
}
});
// 初始化通知
if ((musics != null) && current_position < musics.size()) {
Music music = musics.get(current_position);
initNotification();
showNotification(null, music.getTitle(), music.getArtist());
}
}
/**
* 实现自己的广播接收器
*/
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
String action = arg1.getAction();
if (Constant.ACTION_CONTROL.equals(action)) {
playOrPauseMusic();
} else if (Constant.ACTION_LAST.equals(action)) {
lastMusic();
} else if (Constant.ACTION_NEXT.equals(action)) {
nextMusic();
} else if (Constant.ACTION_CLOSE_NOTIFICATION.equals(action)) {
closeNotification();
} else if (Constant.ACTION_PLAY_MODE.equals(action)) {
play_mode = ++play_mode % 3;
Intent broadcast = new Intent(Constant.ACTION_CHANGED_MODE);
sendBroadcast(broadcast);
} else if (Constant.ACTION_SEEK_TO.equals(action)) {
current_position = arg1.getIntExtra(
Constant.KEY_MUSIC_POSITION, current_position);
playMusic(current_position);
}
}
};
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
suiside();
}
/**
* 自杀
*/
private void suiside() {
isPlaying = false;
if (mMediaPlayer != null) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}
mMediaPlayer.release();
}
unregisterReceiver(mReceiver);
setPosition();
setPlayMode();
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
mHandler = null;
}
}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
/**
* 启动Delay线程,用于显示当前歌曲时间
*/
private void startDelayThread() {
isPlaying = true;
new DelayThread().start();
}
/**
* 开始暂停
*/
private void playOrPauseMusic() {
if (mMediaPlayer == null) {
return;
}
if (mMediaPlayer.isPlaying()) {
isPlaying = false;
mMediaPlayer.pause();
// 改变通知里控制按钮为播放
notification.contentView.setImageViewResource(
R.id.iv_control_notification, R.drawable.notification_play);
mNotificationManager.notify(ID, notification);
} else {
// 改变通知里控制按钮为暂停
notification.contentView
.setImageViewResource(R.id.iv_control_notification,
R.drawable.notification_pause);
mNotificationManager.notify(ID, notification);
if (isFirstTime) {
playMusic(current_position);
isFirstTime = false;
return;
}
mMediaPlayer.start();
startDelayThread();
}
}
/**
* 播放音乐MediaPlayer
*
* @param position
*/
private void playMusic(int position) {
if (mMediaPlayer == null) {
return;
}
if (musics == null || musics.size() <= 0) {
return;
}
if (position < 0) {
position = musics.size() - 1;
}
if (position >= musics.size()) {
position = 0;
}
Music music = musics.get(position);
try {
mMediaPlayer.reset();
mMediaPlayer.setDataSource(music.getData());
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.prepare();
mMediaPlayer.start();
startDelayThread();
} 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();
}
showNotification(null, music.getTitle(), music.getArtist());
/**
* 通知PlayActivity
*/
Intent broadcast = new Intent(Constant.ACTION_INFORMATION);
sendBroadcast(broadcast);
}
/**
* 上一曲
*/
private void lastMusic() {
int position = current_position - 1;
if (position < 0) {
position = musics.size() - 1;
}
current_position = position;
playMusic(position);
}
/**
* 下一曲
*/
private void nextMusic() {
int position = current_position + 1;
if (position >= musics.size()) {
position = 0;
}
current_position = position;
playMusic(position);
}
public boolean getPlayState() {
return isPlaying;
}
public int getNowPlayMode() {
return play_mode;
}
/**
* 快进到相应的位置
*
* @param process
*/
public void seekTo(int process) {
mMediaPlayer.seekTo(process);
}
}
PlayActivity.java
package com.leo.lovemusic.activity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import com.leo.lovemusic.R;
import com.leo.lovemusic.bean.Music;
import com.leo.lovemusic.service.PlayService;
import com.leo.lovemusic.util.Constant;
import com.leo.lovemusic.util.Tool;
@SuppressLint("HandlerLeak")
public class PlayActivity extends Activity {
// 附加功能控件
private View back_play = null;
private View more_play = null;
private View favourite_play = null;
private View cycle_play = null;
private View download_play = null;
private View share_play = null;
private View list_play = null;
// 显示内容控件
private TextView title_play = null;
private TextView current_play = null;
private TextView duration_play = null;
// 进度控件
private SeekBar time_play = null;
// 控制控件
private Button last_play = null;
private Button next_play = null;
private Button control_play = null;
// private RelativeLayout container_play = null;
private RelativeLayout container_play = null;
// 更新UI
private Handler mHandler = null;
private PlayService mPlayService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
// super.handleMessage(msg);
switch (msg.what) {
case Constant.WHAT_INFORMATION:
showInformation();
break;
case Constant.WHAT_CONTROL:
changeControl();
break;
case Constant.WHAT_CURRENT_TIME:
setSeekBar(msg.arg1);
break;
}
}
};
initData();
}
private void setSeekBar(int progress) {
time_play.setProgress(progress);
current_play.setText(Tool.formatTime(progress));
}
/**
* 初始化数据
*/
private void initData() {
findViewsById();
registerTheReceiver();
mPlayService = PlayService.getMyself();
showInformation();
changeControl();
changePlayMode();
}
private void registerTheReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Constant.ACTION_CONTROL);
filter.addAction(Constant.ACTION_INFORMATION);
filter.addAction(Constant.ACTION_CURRENT_TIME);
filter.addAction(Constant.ACTION_CHANGED_MODE);
registerReceiver(mBroadcastReceiver, filter);
}
private void changeControl() {
if (mPlayService.getPlayState()) {
control_play.setBackgroundResource(R.drawable.play_play_bg);
} else {
control_play.setBackgroundResource(R.drawable.play_pause_bg);
}
}
/**
* 显示音乐内容
*
* @param duration
*/
private void showInformation() {
if (mPlayService.musics == null || mPlayService.musics.size() <= 0) {
return;
}
if (mPlayService.current_position < 0) {
mPlayService.current_position = mPlayService.musics.size() - 1;
}
if (mPlayService.current_position >= mPlayService.musics.size()) {
mPlayService.current_position = mPlayService.musics.size() - 1;
}
Music music = mPlayService.musics.get(mPlayService.current_position);
if (music == null) {
return;
}
title_play.setText(music.getTitle());
current_play.setText(Tool.formatTime(0));
duration_play.setText(Tool.formatTime(music.getDuration()));
time_play.setMax(music.getDuration());
time_play.setProgress(0);
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
String action = arg1.getAction();
if (Constant.ACTION_CONTROL.equals(action)) {
mHandler.sendEmptyMessage(Constant.WHAT_CONTROL);
} else if (Constant.ACTION_INFORMATION.equals(action)) {
int duration = arg1.getIntExtra(Constant.KEY_DURATION, 0);
Message msg = new Message();
msg.what = Constant.WHAT_INFORMATION;
msg.arg1 = duration;
mHandler.sendMessage(msg);
} else if (Constant.ACTION_CURRENT_TIME.equals(action)) {
int time = arg1.getIntExtra(Constant.KEY_CURRENT_TIME, 0);
Message msg = new Message();
msg.what = Constant.WHAT_CURRENT_TIME;
msg.arg1 = time;
mHandler.sendMessage(msg);
} else if (Constant.ACTION_CHANGED_MODE.equals(action)) {
changePlayMode();
}
}
};
private float beginX = 0;
private float endX = 0;
private void changeContent() {
if (Math.abs(endX - beginX) >= 10) {
Toast.makeText(this, "滑动了:" + (endX - beginX), Toast.LENGTH_SHORT)
.show();
}
}
/**
* 得到所有需要用到的控件并绑定事件
*/
private void findViewsById() {
container_play = (RelativeLayout) findViewById(R.id.rl_container_play);
container_play.setOnTouchListener(new OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View arg0, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
beginX = event.getX();
break;
case MotionEvent.ACTION_UP: {
endX = event.getX();
changeContent();
}
break;
default:
break;
}
return false;
}
});
// addition
back_play = findViewById(R.id.v_back_play);
more_play = findViewById(R.id.v_more_play);
favourite_play = findViewById(R.id.v_favourite_play);
cycle_play = findViewById(R.id.v_cycle_play);
download_play = findViewById(R.id.v_download_play);
share_play = findViewById(R.id.v_share_play);
list_play = findViewById(R.id.v_list_play);
// show
title_play = (TextView) findViewById(R.id.tv_title_play);
current_play = (TextView) findViewById(R.id.tv_current_play);
duration_play = (TextView) findViewById(R.id.tv_duration_play);
// time
time_play = (SeekBar) findViewById(R.id.sb_time_play);
// control
last_play = (Button) findViewById(R.id.btn_last_play);
next_play = (Button) findViewById(R.id.btn_next_play);
control_play = (Button) findViewById(R.id.btn_control_play);
back_play.setOnClickListener(mOnClickListener);
more_play.setOnClickListener(mOnClickListener);
favourite_play.setOnClickListener(mOnClickListener);
cycle_play.setOnClickListener(mOnClickListener);
download_play.setOnClickListener(mOnClickListener);
share_play.setOnClickListener(mOnClickListener);
list_play.setOnClickListener(mOnClickListener);
last_play.setOnClickListener(mOnClickListener);
next_play.setOnClickListener(mOnClickListener);
control_play.setOnClickListener(mOnClickListener);
time_play.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
mPlayService.seekTo(arg0.getProgress());
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
@Override
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
// TODO Auto-generated method stub
}
});
}
/**
* 单击事件监听器
*/
private View.OnClickListener mOnClickListener = new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
int id = arg0.getId();
switch (id) {
case R.id.v_back_play:
Toast.makeText(PlayActivity.this, "back", Toast.LENGTH_SHORT)
.show();
break;
case R.id.v_more_play:
Toast.makeText(PlayActivity.this, "more", Toast.LENGTH_SHORT)
.show();
break;
case R.id.v_favourite_play:
Toast.makeText(PlayActivity.this, "favourite",
Toast.LENGTH_SHORT).show();
break;
case R.id.v_cycle_play: {
Intent intent = new Intent(Constant.ACTION_PLAY_MODE);
sendBroadcast(intent);
}
break;
case R.id.v_download_play:
Toast.makeText(PlayActivity.this, "download",
Toast.LENGTH_SHORT).show();
break;
case R.id.v_share_play:
Toast.makeText(PlayActivity.this, "share", Toast.LENGTH_SHORT)
.show();
break;
case R.id.v_list_play:
Toast.makeText(PlayActivity.this, "list", Toast.LENGTH_SHORT)
.show();
break;
case R.id.btn_last_play: {
Intent intent = new Intent(Constant.ACTION_LAST);
sendBroadcast(intent);
}
break;
case R.id.btn_next_play: {
Intent intent = new Intent(Constant.ACTION_NEXT);
sendBroadcast(intent);
}
break;
case R.id.btn_control_play: {
Intent intent = new Intent(Constant.ACTION_CONTROL);
sendBroadcast(intent);
}
break;
default:
Toast.makeText(PlayActivity.this, "我真的不知道你对我做了什么",
Toast.LENGTH_SHORT).show();
break;
}
}
};
private void changePlayMode() {
int mode = mPlayService.getNowPlayMode();
if (mode == 0) {
cycle_play.setBackgroundResource(R.drawable.play_mode_cycle);
} else if (mode == 1) {
cycle_play.setBackgroundResource(R.drawable.play_mode_single);
} else if (mode == 2) {
cycle_play.setBackgroundResource(R.drawable.play_mode_random);
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(mBroadcastReceiver);
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
mHandler = null;
}
}
}
MyAdapter.java
package com.leo.lovemusic.adapter;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.leo.lovemusic.R;
import com.leo.lovemusic.bean.Music;
import com.leo.lovemusic.letter.LetterBaseListAdapter;
/**
* @time 2015-09-15
* @describe 显示音乐列表的Adapter 此列表同时显示ABCDE等索引
* @author r00kie
*
*/
public class MyAdapter extends LetterBaseListAdapter<Music> {
private static final String LETTER_KEY = "letter";//索引的key
private LayoutInflater mLayoutInflater;//为了布局
/**
* 构造数据源
* @param context
* @param data
*/
public MyAdapter(Context context, List<Music> data) {
super();
mLayoutInflater = LayoutInflater.from(context);
setContainerList(data);
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public String getItemString(Music t) {
// TODO Auto-generated method stub
return t.getTitle();
}
@Override
public Music create(char letter) {
// TODO Auto-generated method stub
return new Music(LETTER_KEY, String.valueOf(letter));
}
/**
* 判断是不是索引
*/
@Override
public boolean isLetter(Music t) {
// TODO Auto-generated method stub
return LETTER_KEY.equals(t.getTitle());
}
/**
* 得到索引布局
*/
@Override
public View getLetterView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
// 这里是字母的item界面设置.
ViewHolder mViewHolder;
if (null == convertView) {
mViewHolder = new ViewHolder();
convertView = mLayoutInflater.inflate(R.layout.letter_index_item,
null);
mViewHolder.index_name = (TextView) convertView
.findViewById(R.id.index_name);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
mViewHolder.index_name.setText(list.get(position).getLetter());
return convertView;
}
/**
* 得到内容的布局
*/
@Override
public View getContainerView(int position, View convertView,
ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder mViewHolder;//这样写是为了优化列表
if (null == convertView) {
mViewHolder = new ViewHolder();
convertView = mLayoutInflater.inflate(R.layout.letter_music_item,
null);
mViewHolder.item_name = (TextView) convertView
.findViewById(R.id.item_name);
mViewHolder.item_value = (TextView) convertView
.findViewById(R.id.item_value);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
mViewHolder.item_name.setText(list.get(position).getTitle());
mViewHolder.item_value.setText(list.get(position).getArtist());
return convertView;
}
private class ViewHolder {
public TextView index_name;
public TextView item_name;
public TextView item_value;
}
}
三、运行原型
四、评价原型
优点:
挺好看的,嘿嘿。我又自恋了。其实就是还好啊,里面的图片都是从QQ音乐里抠图出来的。可以完成基本的功能。
缺点:
有Bugs。
功能不完善,比如:频谱显示没有 摇一摇没有 定时没有等等。
对于原型评价必须要客观,这个需要用户去协助完成。我们快速做出原型就是为了让用户去真真正正的感受,让他们去对真正需要的东西有一个真实的体验,没有的要加,有的不好的要改。这样真的需求明了了,咱们的项目也就好完成了。原型出来了,核心代码也差不多了。
五、修改原型
这个就留给大家去完成了。大家可以根据自己的需要添加好玩的功能。
源码:http://download.csdn.net/detail/zhaicaixiansheng/9109717
六、项目总结
让我们先看一下百度百科里的快速原型的步骤:
快速分析
在分析人员与用户密切配合下,迅速确定系统的基本需求,根据原型所要体现的特征描述基本需求以满足开发原型的需要。
构造原型
在快速分析的基础上,根据基本需求说明尽快实现一个可行的系统。这里要求具有强有力的软件工具的支持,并忽略最终系统在某些细节上的要求,如安全性、坚固性、例外处理等等,主要考虑原型系统能够充分反映所要评价的特性,而暂时删除一切次要内容。
运行原型
这是发现问题、消除误解、开发者与用户充分协调的一个步骤。
评价原型
在运行的基础上,考核评价原型的特性,分析运行效果是否满足用户的愿望,纠正过去交互中的误解与分析中的错误,增添新的要求,并满足因环境变化或用户的新想法引起的系统要求变动,提出全面的修改意见。
原型修改
根据评价原型的活动结果进行修改。若原型未满足需求说明的要求,说明对需求说明存在不一致的理解或实现方案不够合理,则根据明确的要求迅速修改原型。
现说说项目吧!对于初学者,本项目可以起到如下作用:1、android基本知识点的巩固;2、android知识点的混合使用;3、项目的基本结构;对于大神,我就不知道了。不要吵笑我就是了,我会努力的。
对于一个项目有如下告诫:
1、一定要按照命名规则进行命名,比如布局文件要以activity_xx.xml命名,ListView的item要以item_xx.xml命名,id要以tv_show_main命名等。这个可以参考:。然后根据自己的习惯稍作调整。然后坚持使用;
2、一定要习惯注释,因为你做一个项目要好久,到后期你有可能又回来改你的代码,这样可以很快速的知道方法的作用等,还有就是项目交接时,方便接收人快速消化;
3、一定要做好项目的包组织结构,这样程序才不会乱,你才能够有条不紊的进行开发。
这些就是你的代码风格!!!有自己的风格,才有自己的天地,才有自己的乐趣。
为成为一名优秀的程序员而奋斗!!!今天就到这里,谢谢您的阅读。