音乐播放器的实现 -思路整理-(3)

一。主要 Activity分析 

先分析三个主要 的 Activity 。

(1)  一个是打开程序时的 Tab 界面 --- PlayerActivity 

(2) Tab 中第一个 Spec  界面  --------MusicListActivity 

(3) 点击 MusicListActivity 的一个 Item 后,进入 播放界面 -------OnPlayActivity 

下面,我们分析三个主要界面 的实现 方法



二。打开程序时的 Tab 界面 --- PlayerActivity 

    这个 界面我们继承自 TabActivity,里面的 几个 Tab 都 是intent 类型的。

这个 界面 并无消息传递的功能 ,只是一个显示 的功能 ,我们也没有给其加入菜单,而是将菜单加在其 Tab 中。

所以我们注意的有 其 xml 文件的实现 。文件结构 如下图

230020_GA5r_1758208.jpg

  如果 Tab 是用 Intent ,则 tabcontent 下面可以 没有tab1 什么的。

使用 intent 的主要 java 代码 如下:

Resources res= getResources();
TabHost  tabHost =getTabHost();
TabSpec spec;
Intent intent;
		
intent= new Intent().setClass(getBaseContext(), MusicListActivity.class);
spec =tabHost.newTabSpec("音乐").setIndicator("音乐",
res.getDrawable(R.drawable.media_music)).setContent(intent);
                    tabHost.addTab(spec);

注意,这里不用 setcontentView()。而是直接 添加 到  tabHost 中。

上面 的intent 初始化也可以 用  new Intent (getBaseContext() ,XXX.class);



三 。Tab 中第一个 Spec  界面  --------MusicListActivity 

    这个界面 是TabHost 的第一个 Tab。我 们在这里将加入菜单的功能 。

界面主要功能 有:

(1)显示音乐 List 

    这里我们要定义 一个 MusicAdpater  ,为了保持 Adapter 不变(也就是后面的按下去了后的效果),我们用static 类的Adpater 。且在后面我们

将其加入 到一个 BaseActivity 中。(先不管)

(2)点击后,进入 OnPlayAcvitiy 界面 ,并同时传递所选择的 position 到 OnPlayActivity 中。

细节上的功能 还有,在传递 position 的过程 中,保存下 selected_id  ,以让 选择的 Item 背景为GRAY。这就要用到

musicAdapter.notifyDataSetInvalidated();、

这里的处理比较复杂 ,会涉及到生命周期等


下面我们来分析上面的两个功能 

(1) 为了将  Music 显示到list上,我们要定义一个 Music 类,一个 MusicAdapter 适配器。其中, Music 类的定义采用了 Bean 方法。

Music中主要 的变量如下:

private String title;
	private String singer;
	private String album;
	private String url;
	private long size;
	private long time;
	private String name;

在我们返回 name 的时候 ,可能要变换 下,这里先不管 ,不太重要。


    定义好了 Music 类后,我们就可以很容易得到 Adapter   要的数据 类型---  List<Music> listMusic .

我们定义 了MusicList 类,里面的 getMusicData(Context )用于返回 List<Music > 给 MusicAdapter 。

MusicList 的功能 就是查询手机中的音乐 ,并封装成 Music。查询用到了 ContentResolver。细节上还有要选 出后缀 为 mp3 的音乐 。

同时 ,要补充 的知识 还有音乐URL 的查询方法,这里不细讲。


    最后j  MusicAdapter 的定义 。

主要功能 是将音乐 的数据显示到 List 上面,除了时间的的显示 上要注意下,别的还好。但是,

为了标注下已经选择的 Item, 我们在里面加一个变量  selected_id ,且用  get and set 。以区别。这样 ,里面的变量有:

Context context;
	private List<Music> listMusic;
	private LayoutInflater inflater;
	private int selectedItem =-1;

当遇到 已经选择的 item,我们进行下面的处理:

if (getSelectedItem()==position){
			convertView.setBackgroundColor(Color.GRAY);  //是被点击 的音乐 
		}else {                                                                             //没有点击 的音乐 
			convertView.setBackgroundColor(Color.TRANSPARENT);
			convertView.getBackground().setAlpha(120);
		}
		return convertView;


(2) 在上面 的基础上,我们开始主要 分析  MusicListActivity 

    主要功能 是将 MusicList 数据 用 MusicAdpater  显示 在ListView 上。由于  MusicAdpater 可能 以后 还会用到,可以考虑将其设定为 static 的。

同时 ,考虑到每个 Tab 的菜单都相同 ,我们可以写一个 BaseActivity .具体如下。

public class BaseActivity  extends Activity{
	View convertView ;

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		return super.onOptionsItemSelected(item);
	}
	
}

这样 ,我们可以在 BaseActivity中完成菜单的功能 ,同时 ,由于 我们定义 了convertView .以后 Activity 中使用的方法为

super.onCreate(savedInstanceState);
convertView = LayoutInflater.from(this ).inflate(R.layout.music_list, null);
convertView.setBackgroundDrawable(null); //此处可以 加入背景图片
setContentView(convertView);

为了将 选择的音乐 的  id 传递给 OnPlayActivity (OnPlayActivity 再传递给 PalyService )。在监听器中有:

OnItemClickListener ItemClick=new OnItemClickListener() {
		@Override
		public void onItemClick(AdapterView<?> parent, View v, int position,
				long id ) {
			// TODO Auto-generated method stub
			musicAdapter.setSelectedItem(position);
			musicAdapter.notifyDataSetInvalidated();
			//使Adapter 在之后 不再改变 ,只能保证在Activity没有退出时的,如果 退出 了,
			//则会再次运行 onStart() ;
			Intent i = new Intent(getBaseContext(), OnPlayActivity.class);
			i.putExtra("id", position);
			startActivity(i);
		}
	};

如果 这个 Activity 退出 了,怎么还保持 选 的 Item 背景色不同呢, 由Activity 的生命周期,我们应该在 onStart()中完成 这个 功能 ,如下

@Override
	protected void onStart() {
		// TODO Auto-generated method stub
		musicAdapter.setSelectedItem(PlayService.current_id);
		musicAdapter.notifyDataSetInvalidated();
		super.onStart();
	}

要注意的是,此时 musicAdapter 设定的 selected_id 是我们从 PlayService 中读取的。

(selected_id 的最后销毁在  Menu 方法 closeApp()里)

(PlayService   中的变量 current_id 类型为

public static volatile int currentId = -1;

原因有:a. 用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。

             b. 一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。以下例子展现了volatile的作用:用volatile修饰的

变量,线程在每次使用变量的时候,都会读取变量修改后的最的值.)


四。音乐播放界面 --OnPlayActivity 

    OnPlayActivity 从前面的 MusicListActivity 中得到消息只有一个---所选择的音乐。

这里,我们要完成 的主要 功能 有

(1) 完成音乐 的显示 ,先只显示歌名与歌手 。这里我们要先得到 musicList ,再得到 传递进来 的  id 以得到 所选择的  music ,我们在 initView ()方法中完成 。

private void initView() {
		// TODO Auto-generated method stub
		music_name= (TextView) findViewById(R.id.music_name);
		music_singer= (TextView) findViewById(R.id.music_singer);
		
		musicList = MusicList.getMusicData(getApplicationContext());
		selected_id = getIntent().getIntExtra("id", 1);
		music= musicList.get(selected_id);
		
		music_name.setText(music.getName());
		music_singer.setText(music.getSinger());
	}


(2)音乐播放,也就是 PlayerService 的启动,只用传递消息  selected_id 就可以了,这里我们用 方法  sendServiceID() 来完成 。

private void sendServiceID() {
		// TODO Auto-generated method stub
		Intent i= new Intent(this ,PlayService.class);
		i.putExtra("selected_id", selected_id);
		startService(i);
	}


(3)歌曲进度,声音调节,歌词 ,前一首歌,后一首歌曲 等先不考虑。


五。PlaySerivce 的实现 

 PlayerService 会接收来自 OnPlayActivity 的消息 selected_id .以播放音乐 。






转载于:https://my.oschina.net/chuiyuan/blog/268820

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值