`
siyanglu
  • 浏览: 15178 次
  • 性别: Icon_minigender_2
社区版块
存档分类
最新评论

Android手机音乐播放器的初步实现

 
阅读更多



    习惯于在做事情的时候听一些熟悉的歌,你也许会说,这是一心二用,但有的时候却反而更能让人投入自己的工作中。至少对于我来说是这样,当然他人也许无法理解。或许是为了给自己找个正当的理由听音乐,所以做了这个安卓手机的播放器。在此之前由于搭档有意向的是另一个方面,于是在商量之后,我们决定将二者联合起来。当然,这里写的也许不算严格意义上的通信项目,播放器只是项目的一部分而已。下面是播放器的实现过程。

   这里利用Android jdk中的MediaPlayer这个类来实现。

   先看布局文件:

<?xml version="1.0" encoding="utf-8"?>
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
	<TextView
	android:layout_width="fill_parent"
    android:layout_height="wrap_content"
	android:text="@string/title"
	/>
	<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
	<ImageView
	android:layout_x="7dip"
	android:layout_y="17dip"
	android:layout_width="198dip"
    android:layout_height="198dip"
    android:background="#ffffff"
	/>
	<Button
	android:layout_x="230dip"
	android:layout_y="125dip"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="playlist"
	android:id="@+id/playlist"    
    />
    <Button
	android:layout_x="230dip"
	android:layout_y="70dip"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="choose"
	android:id="@+id/choose"    
    />
	<LinearLayout
	android:layout_x="3dip"
	android:layout_y="230dip"
	android:layout_width="fill_parent"
	android:layout_height="65dip"
	android:orientation="vertical">
	<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="@string/songname"
	android:id="@+id/songname"	
	/>
	<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="@string/record"
	android:id="@+id/record"	
	/>
	<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="@string/artist"
	android:id="@+id/artist"	
	/>	
	</LinearLayout>	
	</AbsoluteLayout>
	
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:gravity="center_horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    >
    <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="start"
	android:id="@+id/start_pause"    
    />
    <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="stop"
	android:id="@+id/stop"    
    />
    <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="next"
	android:id="@+id/next"    
    />
    </LinearLayout>
 	<SeekBar android:id="@+id/seekbar"
 	android:layout_width="300dip"
	android:layout_height="20px" 
	android:layout_gravity="center"	
	 />
	 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:gravity="clip_horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    >
	 <TextView
	 android:layout_width="wrap_content"
	 android:layout_height="wrap_content" 		 
	 android:layout_gravity="left"
	 android:id="@+id/goTime"
	 android:text="@string/original_time"
	 />
	<TextView
	 android:layout_width="wrap_content"
	 android:layout_height="wrap_content" 		 
	android:paddingLeft="244dip"
	 android:id="@+id/totalTime"
	 android:text="@string/original_time"
	 />
	</LinearLayout>
</LinearLayout>

   在这边简单介绍一下。界面没有什么特别的,正是最为normal的一个播放器界面。上左是一个图片框,右面三个按钮。下方三排TextView用于显示歌曲信息,再下面是控制播放的按钮和进度条。

(这里说明一下,图片暂用白色背景代替,音乐播放总时间未获得到是由于本人系统重装,模拟器里的sd卡中无内容导致,与下面的方法无关。)

 

   下面是主界面的activity:

package lsy.mp20120211;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
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;
import android.widget.Toast;

public class MainPanel extends Activity implements Runnable {

	private MediaPlayer mp1 = new MediaPlayer();// 新建的一個播放器對象
	private Button start_pause, stop, next;
	private TextView goTime, totalTime, song, album, artist;
	private SeekBar seek;// 進度條
	private String[] total_tim = new String[2];// 這兩項和時間顯示有關
	private String[] current_tim = new String[2];
	private int t, i = 0;
	private android.os.Handler handler = new android.os.Handler();// 控制線程的Handler
	private boolean userChangeSeek;
	private boolean isStop = true;
	private mainhandler mhandler = new mainhandler();
	private final int CHANGE_SONG = 1;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		/** 得到各組件 */
		seek = (SeekBar) this.findViewById(R.id.seekbar);
		goTime = (TextView) this.findViewById(R.id.goTime);
		totalTime = (TextView) this.findViewById(R.id.totalTime);
		song = (TextView) this.findViewById(R.id.songname);
		album = (TextView) this.findViewById(R.id.record);
		artist = (TextView) this.findViewById(R.id.artist);
		start_pause = (Button) this.findViewById(R.id.start_pause);
		stop = (Button) this.findViewById(R.id.stop);
		next = (Button) this.findViewById(R.id.next);

		// 加载音乐队列
		Tools.addSongs();
		System.out.println("队列里的音乐个数为:" + Tools.songlist.size());

		// 啟動新建音樂的線程
		Thread tt = new Thread(this);
		tt.start();

		// 給按鈕添加監聽器
		start_pause.setOnClickListener(oc1);
		stop.setOnClickListener(oc2);
		next.setOnClickListener(oc3);
		// 進度條拖動的監聽器
		seek.setOnSeekBarChangeListener(osl);
	}


/** 程序運行的run方法 */
	public void run() {
		while (i < Tools.songlist.size()) {
			if (isStop) {
				System.out.println("停止播放" + isStop);
				mhandler.sendEmptyMessage(CHANGE_SONG);
				newPlayer(Tools.songlist.get(i).getUrl());
				System.out.println("完成一遍" + i);
			}
		}
	}



/**
* 新建一個播放器的操作
 */
public void newPlayer(String url) {
	// 新建一個播放器
	isStop = false;
	try {
		//mp1.reset();
		mp1.setDataSource(url);
		mp1.prepare();
		// 得到播放總时间(单位:毫秒)
		t = mp1.getDuration();
		System.out.println("t=" + t);
		// 轉成時間格式
		total_tim = changeInt2Time(t);
		// 顯示總時間
		String total_time = total_tim[0] + ":" +total_tim[1];
		totalTime.setText(total_time);

		// 如果直接下一首则不用点击直接播放
		if (start_pause.getText().equals("pause")) {
			// mp1.prepare();
			mp1.start();
			System.out.println("音乐播放中..." + mp1.isPlaying());
		}

		mp1.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
			public void onCompletion(MediaPlayer arg0) {
				seek.setProgress(0);
				if (Tools.songlist.size() == 0) {
					Toast.makeText(MainPanel.this, "结束", 1000).show();
					mp1.release();
				} else {
					isStop = true;
				}
			}
		});
	} catch (Exception e) {
		System.out.println("找不到文件!!!");
		e.printStackTrace();
	}
}

   这上面只是一部分。在这里要说的是,用 MediaPlayer.setDataSource(url)的方法来创建播放歌曲时,需执行MediaPlayer.prepare()方法,才能使MediaPlayer.getDuration()方法得到正确的音乐播放时间(未prepare时,该方法也能得到一个long型的整数,但是相对来说很大,这里不是很清楚得到的是什么值);而通过MediaPlayer.create()方法创建则不需要。

   下面要说的是控制播放按钮的监听器:

/** 開始和暫停的监听 */
	OnClickListener oc1 = new OnClickListener() {
		public void onClick(View v) {
			try {
				if (start_pause.getText().equals("start")) {
					if (mp1 != null) {
						mp1.stop();
					}
					// 計時
					seek.setMax(t);
					handler.post(time_thread);
					// 播放
					mp1.prepare();
					mp1.start();
					start_pause.setText("pause");
					System.out.println("音乐播放中..." + mp1.isPlaying());

				} else if (start_pause.getText().equals("pause")) {
					// 暫停
					mp1.stop();
					start_pause.setText("start");
					handler.removeCallbacks(time_thread);
					System.out.println("暂停" + mp1.isLooping());
				}
			} catch (Exception e) {
				System.out.println("播放发生异常...");
				e.printStackTrace();
			}
		}
	};
	/** 停止按鈕的監聽 */
	OnClickListener oc2 = new OnClickListener() {
		public void onClick(View v) {
			mp1.stop();
			handler.removeCallbacks(time_thread);
			seek.setProgress(0);
			isStop = true;
			goTime.setText("00:00");
			start_pause.setText("start");
		}
	};
	/** 下一首按鈕的監聽 */
	OnClickListener oc3 = new OnClickListener() {
		public void onClick(View v) {
			mp1.stop();
			seek.setProgress(0);
			goTime.setText("00:00");
			i = 1;
			isStop = true;
		}
	};

  

   播放过程中需要另一个线程来同步控制进度条的移动,这里用安卓特有的Handler来控制。

/** 時間進度條的線程 */
	private Runnable time_thread = new Runnable() {
		public void run() {
			// 設置進度
			int current = seek.getProgress() + 1000;
			seek.setProgress(current);
			// 設置目前播放時間
			int cur_time = mp1.getCurrentPosition();
			// 轉換格式使之顯示在介面上
			current_tim = changeInt2Time(cur_time);
			goTime.setText(current_tim[0] + ":" + current_tim[1]);
			// 控制線程
			handler.postDelayed(time_thread, 1000);
		}
	};

 

  此外,当玩家拖动进度条时,相应的歌曲进度也将随之匹配变化。

/** 拖動進度條時對進度條的監聽 */
	OnSeekBarChangeListener osl = new OnSeekBarChangeListener() {
		// 進度改變時的動作
		public void onProgressChanged(SeekBar seekBar, int progress,
				boolean fromUser) {
			fromUser = userChangeSeek;
			// 設置音樂播放與進度匹配
			mp1.seekTo(progress);
			current_tim = changeInt2Time(progress);
			goTime.setText(current_tim[0] + ":" + current_tim[1]);
		}

		// 觸摸進度條時的監聽
		public void onStartTrackingTouch(SeekBar seekBar) {
		}

		// 停止觸摸時的監聽
		public void onStopTrackingTouch(SeekBar seekBar) {
			userChangeSeek = true;
		}
	};

 最后,是一个刷新主线程UI的Handler。Android与普通java工程不同之处的在于,对于一个activity,它自带一个管理主界面的runnable,因此不允许其他的子线程随意刷新主界面。如果你尝试在自定义的线程中刷新界面,则系统会给你报出CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views这个错误。于是我们重新写了handleMessage的方法。


 

/** 新建一个主线程中的handler */
	private class mainhandler extends android.os.Handler {
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			int what = msg.what;
			switch (what) {
			case CHANGE_SONG: {
				// 切換下一首歌曲時,用來刷新主界面UI
				song.setText("   歌曲:  " + Tools.songlist.get(i).getName());
				album.setText("   专辑:  " + Tools.songlist.get(i).getAlbum());
				artist.setText("艺术家:  " + Tools.songlist.get(i).getArtist());
			}
			}
		}
	}

 

   这里还有一个无关紧要的方法,也就是把时间的毫秒形式转换成我们习惯的格式。

/**
	 * 把時間的毫秒形式改成xx:xx
	 * 
	 * @param t
	 */
	public String[] changeInt2Time(int t) {
		int s, min = 0;
		String[] time = new String[2];
		String minutes, seconds;
		s = t / 1000;
		if (s >= 60) {
			min = s / 60;
			s = s % 60;
		}
		// 將分秒轉為字符串
		if (s < 10) {
			seconds = "0" + s;
		} else {
			seconds = s + "";
		}
		if (min < 10) {
			minutes = "0" + min;
		} else {
			minutes = min + "";
		}
		time[0] = minutes;
		time[1] = seconds;
		return time;
	}

 到了这里,一个简单的播放器就完成了。这里仅仅是整个项目的一部分,此外还有播放列表和歌曲的选择以及与电脑通信中歌曲的下载等等,这里暂时不写了。

 

  • 大小: 31 KB
分享到:
评论
3 楼 JuliaAilse 2012-03-11  
厉害啊!2楼正解啊,最好是用自己的照片当专辑封面,假装下是“我的专辑”。哈哈哈!
2 楼 云初静 2012-03-10  
我也想写个播放器了,哈哈。用自己写的播放器听歌,多爽呀,嘿嘿!之前老没有自己想做的东西。
1 楼 yangzhizhen 2012-03-10  
牛。。。。。

相关推荐

    基于Android的音乐播放器的设计与实现设计说明.doc

    ### 基于Android的音乐播放器的设计与实现 #### 一、项目背景与目标 在移动互联网时代,智能手机已经成为人们生活中不可或缺的一部分。随着技术的进步和用户需求的多样化,各种功能强大的应用程序应运而生,其中...

    Android音乐播放器毕业论文.doc

    此毕业设计项目聚焦于Android平台上的音乐播放器应用程序设计与实现,采用Android开源系统技术,利用Java语言和Eclipse编辑工具进行开发,并且详细记录了系统设计过程、界面展示以及主要功能运行流程等内容。...

    安卓音乐播放器简单易懂

    描述中的“简单易懂”意味着这个项目旨在以易于理解和实现的方式介绍Android音乐播放器的构建过程。开发者可能会通过简洁的代码结构和清晰的注释来帮助学习者逐步了解各个功能的实现。 【标签】:“安卓” "安卓...

    java百度音乐播放器源码-HappyPlayer-PC:乐乐音乐播放器,支持ape,wav,flac,mp3等多种格式,支持动态ksc、hr

    2017-09-26:初步实现多行歌词优化。 2017-0-25:注释多行歌词(多行歌词还要想一下怎样实现)。实现桌面歌词(双行歌词)支持显示翻译歌词和音译歌词。 2017-09-24:添加音译歌词功能(暂时不支持预览,有兴趣可到...

    MOTO A1200 移植 Android

    1. **多媒体娱乐中心**:利用Android丰富的应用生态,将MOTO A1200作为音乐播放器或电子书阅读器使用。 2. **智能家居控制终端**:通过安装智能家居应用,实现对家中智能设备的远程控制。 3. **教育学习工具**:为...

    百度CarLife车机手机互联方案接入详细指南,手机连接汽车百度carlife,Java源码.zip

    百度CarLife是一款由百度公司开发的车载智能互联系统,旨在实现手机与汽车之间的无缝连接,为用户提供便捷的导航、音乐播放、电话控制等车载功能。本指南将深入讲解如何接入百度CarLife车机手机互联方案,以Java源码...

    SpotifyStreamer:Android Developer Nanodegree的专案1和2

    `SpotifyStreamer`是Android Developer Nanodegree课程中的一个项目,旨在帮助学生通过实践掌握Android应用开发的基础知识,特别是针对音乐流媒体服务的实现。这个项目分为两个阶段,每个阶段都有特定的特性和功能,...

    Andiod从1.0到3.0各版本的发行时间及特点

    基于Linux Kernel 2.6.27,1.5版引入了视频拍摄和播放、立体声音蓝牙耳机支持、WebKit技术的浏览器、GPS性能提升、虚拟键盘、音乐播放器和相框小部件、自动屏幕旋转等改进。此外,用户界面得到优化,如Gmail可批量...

    行业分类-设备装置-在呈现多媒体内容的同时呈现消息传送内容的系统和方法.zip

    这种技术通常应用于智能设备,如智能手机、平板电脑或者智能电视,它允许用户在享受多媒体服务(如观看视频、听音乐或浏览图片)的同时接收和处理消息。 在描述中,尽管信息简洁,但我们可以推断出这是一个旨在提高...

    谢伟-基于iPhone开发实践 pdf

    4. **娱乐媒体**:音乐播放器、视频流媒体等,提供丰富的多媒体内容。 5. **健康与健身**:监测健康数据、跟踪健身计划的应用程序。 #### 三、iPhone开发市场现状分析 1. **市场规模**:随着智能手机用户的增长,...

Global site tag (gtag.js) - Google Analytics