mp3播放器的实现

 

1.首先看看实现MP3播放器的功能的布局文件

1.欢迎界面的布局startimage.xml

 

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/startimage"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true"
    android:src="@drawable/hello" >

</ImageView>

2.网络歌曲和本地歌曲的布局的主布局main.xml

 

 

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_alignParentBottom="true"
    android:background="@drawable/bg" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:padding="5dp" >

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true" />

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="5dp" />
    </LinearLayout>

</TabHost>

3.网络歌曲的布局intent_mp3_list.xml

 

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/listLinearLayout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <ListView
            android:id="@id/android:list"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:drawSelectorOnTop="false"
            android:scrollbars="vertical" />
    </LinearLayout>

</LinearLayout>

4,本地歌曲列表的布局local_mp3_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/listLinearLayout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <ListView
            android:id="@id/android:list"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:drawSelectorOnTop="false"
            android:scrollbars="vertical" />
    </LinearLayout>

</LinearLayout>

5.是音乐播放界面的布局player.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:paddingBottom="1dip"
    android:paddingLeft="10dip"
    android:paddingRight="10dip"
    android:paddingTop="1dip" 
    android:gravity="center_vertical"
    android:background="@drawable/bg">
    
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="350dp"
    android:orientation="vertical">
    <ImageView 
        android:id="@+id/image"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/images"
        />

    
    <TextView
        android:id="@+id/lrcText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="歌词:" 
        android:textColor="#FF6100"
        android:textSize="20dp"/>
    </LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
     android:gravity="center_horizontal">
    
    <ImageButton
        android:id="@+id/pause"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/pause" />

    <ImageButton
        android:id="@+id/begin"
         android:paddingLeft="10dip"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/begin" />
    
    <ImageButton
        android:id="@+id/stop"
        android:paddingLeft="10dip"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/stop" />
</LinearLayout>
</LinearLayout>

6.是关于音乐信息的布局mp3info_item.xml

 

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
    android:paddingBottom="1dip"
    android:paddingLeft="10dip"
    android:paddingRight="10dip"
    android:paddingTop="1dip" >

    <TextView
        android:id="@+id/mp3_name"
        android:layout_width="180dip"
        android:layout_height="30dip"
        android:textSize="10pt" />

    <TextView
        android:id="@+id/mp3_size"
        android:layout_width="180dip"
        android:layout_height="30dip"
        android:textSize="10pt" />

</LinearLayout>


2,布局看完了后咱就可以看看实现的代码了

 

7,首先看看第一个欢迎界面的代码startAnimation.java

 

package com.wang.Activity;


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;

public class startAnimation extends Activity {
	ImageView startimage;
	AlphaAnimation startAnimation;

	protected void onCreate(Bundle savedInstanceState) {
		// 去除标题
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		// 取消状态栏,充满全屏
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		super.onCreate(savedInstanceState);
		setContentView(R.layout.startimage);

		startimage = (ImageView) findViewById(R.id.startimage);
		// 设置动画的渐变效果逐渐增强
		startAnimation = new AlphaAnimation(0.5f, 2.5f);
		// 设置动画显示的时间为3s
		startAnimation.setDuration(3000);
		// 开始动画效果
		startimage.startAnimation(startAnimation);
		// 为动画效果设置监听事件
		startAnimation.setAnimationListener(new AnimationListener() {
			// ka开始
			@Override
			public void onAnimationStart(Animation animation) {
				// TODO Auto-generated method stub

			}

			// 重复
			@Override
			public void onAnimationRepeat(Animation animation) {
				// TODO Auto-generated method stub

			}

			// 动画结束
			@Override
			public void onAnimationEnd(Animation animation) {

				// 声明一个意图,启动一个新的Activity
				Intent intent = new Intent(startAnimation.this,
						MainActivity.class);
				// 启动新的Activity
				startActivity(intent);
			}
		});
	}

}

8.动画结束后就回跳转到下一个界面mainActivity.java

 

 

package com.wang.Activity;


import android.app.TabActivity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TabHost;

public class MainActivity extends TabActivity {

	protected void onCreate(Bundle savedInstanceState) {
		// 去除标题
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		// 取消状态栏,充满全屏
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		// 得到TabHost对象
		TabHost tabHost = getTabHost();
		// 生成一个Intent对象
		Intent remoteIntent = new Intent();
		// 启动一个新的activity
		remoteIntent.setClass(this, Mp3ListActivity.class);
		// 一个TabSpec对象 代表了一个页
		TabHost.TabSpec remoteSpec = tabHost.newTabSpec("网络歌曲");
		Resources res = getResources();
		// 设置该页的indicator
		remoteSpec.setIndicator("网络歌曲", res.getDrawable(R.drawable.internet));
		// 设置该页的内容
		remoteSpec.setContent(remoteIntent);
		tabHost.addTab(remoteSpec);

		// 得到第二个页面
		Intent localIntent = new Intent();
		// 启动一个新的activity
		localIntent.setClass(this, LocalMp3ListActivity.class);
		// 声明一个新的页面
		TabHost.TabSpec localSpec = tabHost.newTabSpec("本地歌曲");
		// s设置该页的indicator
		localSpec.setIndicator("本地歌曲", res.getDrawable(R.drawable.local));
		// 设置内容
		localSpec.setContent(localIntent);
		tabHost.addTab(localSpec);

	}
}


9.这个界面分为两页,一页是网络歌曲,一页是本地歌曲首先看看网络歌曲的实现MP3listactivity.java

 

 

package com.wang.Activity;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import com.wang.download.HttpDownloader;
import com.wang.service.DownloadService;
import com.wang.xml.Mp3Info;
import com.wang.xml.Mp3ListContentHandler;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class Mp3ListActivity extends ListActivity {
	private static final int UPDATE = 1;
	private static final int ABOUT = 2;
	private List<Mp3Info> mp3Infos = null;

	// 在用点击MENU按钮之后,实现歌曲列表更新

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		menu.add(0, UPDATE, 1, R.string.mp3list_update);
		menu.add(0, ABOUT, 2, R.string.mp3list_about);
		return super.onCreateOptionsMenu(menu);
	}

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

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == UPDATE) {
			updateListView();
		} else if (item.getItemId() == ABOUT) {
			// 用户点击了关于按钮
			Toast.makeText(this, "你好,这是简单的MP3程序!!!", Toast.LENGTH_LONG).show();
		}
		return super.onOptionsItemSelected(item);
	}

	private SimpleAdapter buildSimpleAdapter(List<Mp3Info> mp3Infos) {
		// 生成一个List对象,并按照SimpleAdapter的标准,将mp3Infos当中的数据添加到List当中去
		List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();

		// 返回一个迭代器的元素列表。迭代的元素以相同的顺序出现在列表中。
		for (Iterator iterator = mp3Infos.iterator(); iterator.hasNext();) {
			Mp3Info mp3Info = (Mp3Info) iterator.next();
			// 生成一个HashMap对象,迭代用来遍历的元素
			HashMap<String, String> map = new HashMap<String, String>();
			// s映射输出名字和大小
			map.put("mp3_name", mp3Info.getMp3Name());
			map.put("mp3_size", mp3Info.getMp3Size());
			// 将map追加到list表中
			list.add(map);
		}
		// 创建一个SimpleAdapter对象
		SimpleAdapter simpleAdapter = new SimpleAdapter(this, list,
				R.layout.mp3info_item, new String[] { "mp3_name", "mp3_size" },
				new int[] { R.id.mp3_name, R.id.mp3_size });
		// 将这个SimpleAdapter对象设置到ListActivity当中
		return simpleAdapter;
	}

	private void updateListView() {
		// 用户点击了更新列表按钮
		// 下载包含所有Mp3基本信息的xml文件
		String xml = downloadXML("http://10.254.1.62/demo/resources.xml");
		// 对xml文件进行解析,并将解析的结果放置到Mp3Info对象当中,最后将这些Mp3Info对象放置到List当中
		mp3Infos = parse(xml);
		SimpleAdapter simpleAdapter = buildSimpleAdapter(mp3Infos);
		setListAdapter(simpleAdapter);
	}

	// 下载url资源文件文件
	private String downloadXML(String urlStr) {
		HttpDownloader httpDownloader = new HttpDownloader();
		String result = httpDownloader.download(urlStr);
		return result;
	}

	// SAX进行解析XML文件
	private List<Mp3Info> parse(String xmlStr) {
		// 定义一个SAXParserFactory,获取一个基于SAX的解析器来解析XML文档。
		SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
		// 声明一个ArrayList对象
		List<Mp3Info> infos = new ArrayList<Mp3Info>();
		try {
			/***
			 * XMLReader接口,一个XML解析器的SAX2司机必须实现。 这个接口允许应用程序集和查询的特性和属性在解析器、
			 * 注册事件处理器用于文档处理,启动解析文档。  *
			 ***/
			XMLReader xmlReader = saxParserFactory.newSAXParser()
					.getXMLReader();
			// 声明一个Mp3ListContentHandler对象
			Mp3ListContentHandler mp3ListContentHandler = new Mp3ListContentHandler(
					infos);
			/****
			 *  应用程序可以注册一个新的或不同的处理程序在中间的一个解析 ,SAX解析器必须立即开始使用新的处理程序。 *
			 ***/
			xmlReader.setContentHandler(mp3ListContentHandler);
			/*****
			 * parse解析一个XML文档。   应用程序可以使用这个方法来指导读者开始的XML解析,
			 * 一个XML文档从任何有效的输入源(一个字符流,字节流,或一个URI)。
			 * 应用程序可能无法调用该方法虽然解析过程中(他们应该创建一个新的XMLReader 相反嵌套的每个XML文档)。一旦一个解析完成,
			 * 应用程序可以重用相同的XMLReader对象,可能使用不同的输入源。
			 * XMLReader的配置对象(如处理器绑定和价值观的确立对功能的标志和属性)是未受完成解析,
			 * 除非那方面的定义显式地指定配置的其他行为
			 * 
			 * *
			 ***/
			xmlReader.parse(new InputSource(new StringReader(xmlStr)));
			// 一个个进行迭代的元素这个列表
			for (Iterator iterator = infos.iterator(); iterator.hasNext();) {
				Mp3Info mp3Info = (Mp3Info) iterator.next();
				System.out.println(mp3Info);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return infos;
	}

	// 设置item的单击事件
	protected void onListItemClick(ListView l, View v, int position, long id) {

		// 根据用户点击列表当中的位置来得到响应的Mp3Info对象
		Mp3Info mp3Info = mp3Infos.get(position);
		System.out.println("mp3info" + mp3Info);
		// 生成Intent对象
		Intent intent = new Intent();
		// 将Mp3Info对象存入到Intent对象当中
		intent.putExtra("mp3Info", mp3Info);
		// 跳转到DownloadService.class 进行下载
		intent.setClass(this, DownloadService.class);
		// 启动Service
		startService(intent);
		super.onListItemClick(l, v, position, id);
	}

}

10.接着是本地歌曲的实现代码LocalMp3ListActivity.java

 

 

package com.wang.Activity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.wang.utils.FileUtils;
import com.wang.xml.Mp3Info;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class LocalMp3ListActivity extends ListActivity {
	private List<Mp3Info> mp3Infos = null;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.local_mp3_list);

	}

	@Override
	protected void onResume() {

		// 声明一个文件对象
		FileUtils fileUtils = new FileUtils();
		// 得到文件的位置
		mp3Infos = fileUtils.getMp3Files("mp3/");
		// 用列表进行存储,构造一个新的ArrayList实例初始化为零
		List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
		// 返回一个迭代器的元素这个列表,迭代的元素以相同的顺序出现在列表中
		for (Iterator iterator = mp3Infos.iterator(); iterator.hasNext();) {

			Mp3Info mp3Info = (Mp3Info) iterator.next();
			HashMap<String, String> map = new HashMap<String, String>();
			// 输出指定的内容
			map.put("mp3_name", mp3Info.getMp3Name());
			map.put("mp3_size", mp3Info.getMp3Size());
			// 添加数据到list
			list.add(map);
		}

		// 简单的适配器映射XML文件。
		SimpleAdapter simpleAdapter = new SimpleAdapter(this, list,
				R.layout.mp3info_item, new String[] { "mp3_name", "mp3_size" },
				new int[] { R.id.mp3_name, R.id.mp3_size });
		// 设置simpleAdapter到ListAdapter
		setListAdapter(simpleAdapter);
		super.onResume();
	}

	// 设置item的监听时间
	protected void onListItemClick(ListView l, View v, int position, long id) {
		// 如果不为空列
		if (mp3Infos != null) {
			// 得到位置
			Mp3Info mp3Info = mp3Infos.get(position);

			// 声明一个intent对象
			Intent intent = new Intent();
			// 添加扩展数据的意图
			intent.putExtra("mp3Info", mp3Info);
			// 启动一个新的activity
			intent.setClass(this, PlayerActivity.class);
			// 启动跳转
			startActivity(intent);
		}
	}

}

 

 

11.当你点击一下本地歌曲列表的时候会跳转到音乐播放的界面的实现代码player.java

 

package com.wang.Activity;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Queue;

import com.wang.lrc.LrcProcessor;
import com.wang.service.PlayerService;
import com.wang.xml.Mp3Info;

import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;

public class PlayerActivity extends Activity {
	public static final int PLAY_MSG = 1;
	public static final int PAUSE_MSG = 2;
	public static final int STOP_MSG = 3;
	private ImageButton play_Button, pause_Button, stop_Button;
	private MediaPlayer mediaPlayer;
	private TextView lrcTextView;
	private UpdateTimeCallback updateTimeCallback;
	private Mp3Info mp3Info;
	private ArrayList<Queue> queues = null;
	private long begin = 0;
	private long nextTimeMill = 0;
	private long currentTimeMill = 0;
	private String message = null;
	private long pauseTimeMills = 0;
	//异步
	private Handler handler = new Handler();
	private boolean isPlaying = false;

	protected void onCreate(Bundle savedInstanceState) { 
		// 去除标题
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		// 取消状态栏,充满全屏
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);

		super.onCreate(savedInstanceState);
		setContentView(R.layout.player);
		//得到返回的intent,开始活动
		Intent intent = getIntent();
		//得到一个可以序列化的值
		mp3Info = (Mp3Info) intent.getSerializableExtra("mp3Info");
		//实例化组件
		play_Button = (ImageButton) findViewById(R.id.begin);
		pause_Button = (ImageButton) findViewById(R.id.pause);
		stop_Button = (ImageButton) findViewById(R.id.stop);
		lrcTextView = (TextView) findViewById(R.id.lrcText);
		//设置按钮的监听事件
		play_Button.setOnClickListener(new BeginButton());
		pause_Button.setOnClickListener(new PauseButton());
		stop_Button.setOnClickListener(new StopButton());

	}

	//根据歌词文件的名字,来读取歌词文件当中的信息 

	private void prepareLrc(String lrcName) {
		try {
			//声明一个文件输入流,得到文件的目录、绝对路径下的文件下的文件名称
			InputStream inputStream = new FileInputStream(Environment
					.getExternalStorageDirectory().getAbsoluteFile()
					+ File.separator + "mp3/" + lrcName);
			// 声明一个歌词的对象
			LrcProcessor lrcProcessor = new LrcProcessor();
			//得到歌词进度的输入流
			queues = lrcProcessor.process(inputStream);
			// 创建一个UpdateTimeCallback对象
			updateTimeCallback = new UpdateTimeCallback(queues);
			begin = 0;
			currentTimeMill = 0;
			nextTimeMill = 0;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	class BeginButton implements OnClickListener {

		@Override
		public void onClick(View v) {
			// 创建一个Intent对象,用于同时Service开始播放MP3
			Intent intent = new Intent();
			// 跳转到service进行执行,目的是可以后台执行
			intent.setClass(PlayerActivity.this, PlayerService.class);
			intent.putExtra("mp3Info", mp3Info);
			intent.putExtra("MSG",PLAY_MSG);
			// 读取LRC文件
			prepareLrc(mp3Info.getLrcName());
			// 启动Service
			startService(intent);
			// 将begin的值置为当前毫秒数
			begin = System.currentTimeMillis();
			// 执行updateTimeCallback
			handler.postDelayed(updateTimeCallback, 5);
			isPlaying = true;
		}

	}

	class PauseButton implements OnClickListener {

		@Override
		public void onClick(View v) {
			// 通知Service暂停播放MP3
			Intent intent = new Intent();
			intent.setClass(PlayerActivity.this, PlayerService.class);
			intent.putExtra("MSG",PAUSE_MSG);
			startService(intent);
			//如果正在播放
			if (isPlaying) {
				//g更新可运行的MP3消息对列
				handler.removeCallbacks(updateTimeCallback);
				//返回当前的系统时间
				pauseTimeMills = System.currentTimeMillis();
			} else {
				//使Runnable 添加到消息队列将会在指定时间
				handler.postDelayed(updateTimeCallback, 5);
				//返回当前的系统时间-暂停的时间+上开始的时间
				begin = System.currentTimeMillis() - pauseTimeMills + begin;
			}
			///3目运算符哦按段是否在播放
			isPlaying = isPlaying ? false : true;
		}

	}

	class StopButton implements OnClickListener {

		@Override
		public void onClick(View v) {
			// 通知Service停止播放MP3文件
			Intent intent = new Intent();
			intent.setClass(PlayerActivity.this, PlayerService.class);
			intent.putExtra("MSG", STOP_MSG);
			startService(intent);
			// 从Handler当中移除updateTimeCallback
			handler.removeCallbacks(updateTimeCallback);
		}

	}

	class UpdateTimeCallback implements Runnable {
		Queue times = null;
		Queue messages = null;

		public UpdateTimeCallback(ArrayList<Queue> queues) {
			// 从ArrayList当中取出相应的对象对象
			times = queues.get(0);
			messages = queues.get(1);
		}

		@Override
		public void run() {
			// 计算偏移量,也就是说从开始播放MP3到现在为止,共消耗了多少时间,以毫秒为单位
			long offset = System.currentTimeMillis() - begin;
			if (currentTimeMill == 0) {
				//poll() 方法 是检索并删除队列头上,或者返回null如果这个队列是空的。
				nextTimeMill = (Long) times.poll();
				message = (String) messages.poll();
			}
			if (offset >= nextTimeMill) {
				lrcTextView.setText(message);
				message = (String) messages.poll();
				nextTimeMill = (Long) times.poll();
			}
			currentTimeMill = currentTimeMill + 10;
			handler.postDelayed(updateTimeCallback, 10);
		}

	}
}


12.从网络下载歌曲 的代码实现过程如下:

 

 

package com.wang.download;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import com.wang.utils.FileUtils;

public class HttpDownloader {
	private URL url = null;

	/**
	 * 根据URL下载文件,前提是这个文件当中的内容是文本, 函数的返回值就是文件当中的内容 1.创建一个URL对象
	 * 2.通过URL对象,创建一个HttpURLConnection对象 3.得到InputStram 4.从InputStream当中读取数据
	 */
	public String download(String urlStr) {
		// 声明一个StringBuffer对象
		StringBuffer sb = new StringBuffer();
		String line = null;
		BufferedReader buffer = null;
		try {
			// 创建一个URL对象
			url = new URL(urlStr);
			// 创建一个Http连接
			HttpURLConnection urlConn = (HttpURLConnection) url
					.openConnection();
			// 使用IO流读取数据
			buffer = new BufferedReader(new InputStreamReader(urlConn
					.getInputStream()));
			// 当读到的内容不为空的时候追加一行
			while ((line = buffer.readLine()) != null) {
				sb.append(line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭BufferedReader
				buffer.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return sb.toString();
	}

	/**
	 * 该函数返回整形 -1:代表下载文件出错 0:代表下载文件成功 1:代表文件已经存在
	 */
	public int downFile(String urlStr, String path, String fileName) {
		InputStream inputStream = null;
		try {
			// 声明一个文件对象
			FileUtils fileUtils = new FileUtils();
			// 判断是否存在
			if (fileUtils.isFileExist(fileName, path)) {
				return 1;
			} else {
				// 如果不存在,则从服务器上下载
				inputStream = getInputStreamFromUrl(urlStr);
				// 把文件存入SD卡中,根据URL得到输入流
				File resultFile = fileUtils.writeSDFromInput(path, fileName,
						inputStream);
				if (resultFile == null) {
					return -1;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		} finally {
			try {
				// 关闭输入流文件
				inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return 0;
	}

	// 根据URL得到输入流
	public InputStream getInputStreamFromUrl(String urlStr)
			throws MalformedURLException, IOException {
		// 声明一个URL对象
		url = new URL(urlStr);
		// /打开URL连接
		HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
		// 得到url的输入流
		InputStream inputStream = urlConn.getInputStream();
		return inputStream;
	}
}

13.xml解析的实现过程之Mp3ListContentHandler.java

 

 

package com.wang.xml;

import java.util.List;


import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


public class Mp3ListContentHandler extends DefaultHandler {
	private List<Mp3Info> infos = null;
	private Mp3Info mp3Info = null;
	private String tagName = null;

	public Mp3ListContentHandler(List<Mp3Info> infos) {
		super();
		this.infos = infos;
	}

	public List<Mp3Info> getInfos() {
		return infos;
	}

	public void setInfos(List<Mp3Info> infos) {
		this.infos = infos;
	}

	// 要解析XML文档的字符,开始,及长度
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		String temp = new String(ch, start, length);
		if (tagName.equals("id")) {
			mp3Info.setId(temp);
		} else if (tagName.equals("mp3.name")) {
			mp3Info.setMp3Name(temp);
		} else if (tagName.equals("mp3.size")) {
			mp3Info.setMp3Size(temp);
		} else if (tagName.equals("lrc.name")) {
			mp3Info.setLrcName(temp);
		} else if (tagName.equals("lrc.size")) {
			mp3Info.setLrcSize(temp);
		}
	}
///解析文档结束
public void endDocument() throws SAXException {
	}

	//解析文档中的元素结束
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		if (qName.equals("resource")) {
			infos.add(mp3Info);
		}
		tagName = "";

	}
//开始解析文档
	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		super.startDocument();
	}

	//开始解析文档中的元素
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		this.tagName = localName;
		if (tagName.equals("resource")) {
			mp3Info = new Mp3Info();
		}
	}

}


14..xml解析的实现过程之mp3info.java

 

 

package com.wang.xml;

import java.io.Serializable;

//实现序列化的接口 
public class Mp3Info implements Serializable {
	// 序列化的接口 的ID
	private static final long serialVersionUID = 1L;
	private String id;
	private String mp3Name;
	private String mp3Size;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public Mp3Info() {
		super();
	}

	// 返回内容
	public String toString() {
		return "Mp3Info [id=" + id + ", lrcName=" + lrcName + ", lrcSize="
				+ lrcSize + ", mp3Name=" + mp3Name + ", mp3Size=" + mp3Size
				+ "]";
	}

	public String getMp3Name() {
		return mp3Name;
	}

	// 构造函数
	public Mp3Info(String id, String mp3Name, String mp3Size, String lrcName,
			String lrcSize) {
		super();
		this.id = id;
		this.mp3Name = mp3Name;
		this.mp3Size = mp3Size;
		this.lrcName = lrcName;
		this.lrcSize = lrcSize;
	}

	public void setMp3Name(String mp3Name) {
		this.mp3Name = mp3Name;
	}

	public String getMp3Size() {
		return mp3Size;
	}

	public void setMp3Size(String mp3Size) {
		this.mp3Size = mp3Size;
	}

	public String getLrcName() {
		return lrcName;
	}

	public void setLrcName(String lrcName) {
		this.lrcName = lrcName;
	}

	public String getLrcSize() {
		return lrcSize;
	}

	public void setLrcSize(String lrcSize) {
		this.lrcSize = lrcSize;
	}

	private String lrcName;
	private String lrcSize;

}


15.在SD卡中创建MP3文件夹,以及应用实现代码FileUtils.java

 

 

package com.wang.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import com.wang.xml.Mp3Info;

import android.os.Environment;

public class FileUtils {
	private String SDCardRoot;

	public FileUtils() {
		// 得到当前外部存储设备的目录与路径
		SDCardRoot = Environment.getExternalStorageDirectory()
				.getAbsolutePath()
				+ File.separator;
	}

	// 在SD卡上创建文件
	public File createFileInSDCard(String fileName, String dir)
			throws IOException {
		// 声明对象并创建目录和文件名称
		File file = new File(SDCardRoot + dir + File.separator + fileName);
		file.createNewFile();
		return file;
	}

	// 在SD卡上创建目录
	public File creatSDDir(String dir) {
		File dirFile = new File(SDCardRoot + dir + File.separator);
		System.out.println(dirFile.mkdirs());
		return dirFile;
	}

	// 判断SD卡上的文件夹是否存在
	public boolean isFileExist(String fileName, String path) {
		File file = new File(SDCardRoot + path + File.separator + fileName);
		return file.exists();
	}

	// 将一个InputStream里面的数据写入到SD卡中
	public File writeSDFromInput(String path, String fileName, InputStream input) {

		File file = null;
		OutputStream output = null;
		try {
			// 创建目录
			creatSDDir(path);

			// chu创建文件名称
			file = createFileInSDCard(fileName, path);
			// 声明一个FileOutputStream对象
			output = new FileOutputStream(file);
			// 声明一个字节数组
			byte buffer[] = new byte[4 * 1024];
			int temp;
			// 重写
			while ((temp = input.read(buffer)) != -1) {
				output.write(buffer, 0, temp);
			}
			// 刷新
			output.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				output.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return file;
	}

	// 读取目录中的Mp3文件的名字和大小
	public List<Mp3Info> getMp3Files(String path) {
		List<Mp3Info> mp3Infos = new ArrayList<Mp3Info>();
		// 得到文件的路径
		File file = new File(SDCardRoot + File.separator + path);
		// 返回当前文件夹中的多有对象
		File[] files = file.listFiles();
		FileUtils fileUtils = new FileUtils();
		for (int i = 0; i < files.length; i++) {
			// 判断是否否是MP3结尾
			if (files[i].getName().endsWith("mp3")) {
				Mp3Info mp3Info = new Mp3Info();
				// 得到文件名和大小
				mp3Info.setMp3Name(files[i].getName());
				mp3Info.setMp3Size(files[i].length() + "");
				// 正则表达式
				String temp[] = mp3Info.getMp3Name().split("\\.");
				String eLrcName = temp[0] + ".lrc";
				// 判断文件名是否存在
				if (fileUtils.isFileExist(eLrcName, "/mp3")) {
					mp3Info.setLrcName(eLrcName);
				}
				mp3Infos.add(mp3Info);
			}
		}
		return mp3Infos;
	}

}

16.关于歌词播放的实现功能LrcProcessor.java

 

 

package com.wang.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import com.wang.xml.Mp3Info;

import android.os.Environment;

public class FileUtils {
	private String SDCardRoot;

	public FileUtils() {
		// 得到当前外部存储设备的目录与路径
		SDCardRoot = Environment.getExternalStorageDirectory()
				.getAbsolutePath()
				+ File.separator;
	}

	// 在SD卡上创建文件
	public File createFileInSDCard(String fileName, String dir)
			throws IOException {
		// 声明对象并创建目录和文件名称
		File file = new File(SDCardRoot + dir + File.separator + fileName);
		file.createNewFile();
		return file;
	}

	// 在SD卡上创建目录
	public File creatSDDir(String dir) {
		File dirFile = new File(SDCardRoot + dir + File.separator);
		System.out.println(dirFile.mkdirs());
		return dirFile;
	}

	// 判断SD卡上的文件夹是否存在
	public boolean isFileExist(String fileName, String path) {
		File file = new File(SDCardRoot + path + File.separator + fileName);
		return file.exists();
	}

	// 将一个InputStream里面的数据写入到SD卡中
	public File writeSDFromInput(String path, String fileName, InputStream input) {

		File file = null;
		OutputStream output = null;
		try {
			// 创建目录
			creatSDDir(path);

			// chu创建文件名称
			file = createFileInSDCard(fileName, path);
			// 声明一个FileOutputStream对象
			output = new FileOutputStream(file);
			// 声明一个字节数组
			byte buffer[] = new byte[4 * 1024];
			int temp;
			// 重写
			while ((temp = input.read(buffer)) != -1) {
				output.write(buffer, 0, temp);
			}
			// 刷新
			output.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				output.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return file;
	}

	// 读取目录中的Mp3文件的名字和大小
	public List<Mp3Info> getMp3Files(String path) {
		List<Mp3Info> mp3Infos = new ArrayList<Mp3Info>();
		// 得到文件的路径
		File file = new File(SDCardRoot + File.separator + path);
		// 返回当前文件夹中的多有对象
		File[] files = file.listFiles();
		FileUtils fileUtils = new FileUtils();
		for (int i = 0; i < files.length; i++) {
			// 判断是否否是MP3结尾
			if (files[i].getName().endsWith("mp3")) {
				Mp3Info mp3Info = new Mp3Info();
				// 得到文件名和大小
				mp3Info.setMp3Name(files[i].getName());
				mp3Info.setMp3Size(files[i].length() + "");
				// 正则表达式
				String temp[] = mp3Info.getMp3Name().split("\\.");
				String eLrcName = temp[0] + ".lrc";
				// 判断文件名是否存在
				if (fileUtils.isFileExist(eLrcName, "/mp3")) {
					mp3Info.setLrcName(eLrcName);
				}
				mp3Infos.add(mp3Info);
			}
		}
		return mp3Infos;
	}

}


17.关于文件下载的服务进程DownloadService.java

 

 

package com.wang.service;

import com.wang.download.HttpDownloader;
import com.wang.xml.Mp3Info;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class DownloadService extends Service{

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	//每次用户点击ListActivity当中的一个条目时,就会调用该方法
	public int onStartCommand(Intent intent, int flags, int startId) {
		//从Intent对象当中将Mp3Info对象取出
		Mp3Info mp3Info = (Mp3Info)intent.getSerializableExtra("mp3Info");
		//生成一个下载线程,并将Mp3Info对象作为参数传递到线程对象当中
		DownloadThread downloadThread = new DownloadThread(mp3Info);
		//启动新线程
		Thread thread = new Thread(downloadThread);
		thread.start();
		return super.onStartCommand(intent, flags, startId);
	}
	//创建一个线程的内部类进行下载
	class DownloadThread implements Runnable{
		private Mp3Info mp3Info = null;
		// 构函数接受mp3info的对象
		public DownloadThread(Mp3Info mp3Info){
			this.mp3Info = mp3Info;
		}
		@Override
		public void run() {
			//根据MP3文件的名字,生成下载地址,并从服务器上下载网络歌曲
			String mp3Url ="http://10.254.1.62/demo" + mp3Info.getMp3Name();
			String lrcUrl ="http://10.254.1.62/demo" + mp3Info.getLrcName();
			//生成下载文件所用的对象
			HttpDownloader httpDownloader = new HttpDownloader();
			//将文件下载下来,并存储到SDCard当中
			int mp3Result = httpDownloader.downFile(mp3Url, "mp3/", mp3Info.getMp3Name());
			int lrcResult = httpDownloader.downFile(lrcUrl, "mp3/", mp3Info.getLrcName());
			String resultMessage = null;
			if(mp3Result == -1){
				resultMessage = "下载失败";
			}
			else if(mp3Result == 0){
				resultMessage = "文件已经存在,不需要重复下载";
			}
			else if(mp3Result == 1){
				resultMessage = "文件下载成功";
			}
		}
		
	}

}


18.关于音乐播放的服务进程PlayerService.java

 

 

package com.wang.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Queue;

import com.wang.lrc.LrcProcessor;
import com.wang.xml.Mp3Info;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;

public class PlayerService extends Service {
	public static final int PLAY_MSG = 1;
	public static final int PAUSE_MSG = 2;
	public static final int STOP_MSG = 3;

	private boolean isPlaying = false;
	private boolean isPause = false;
	private boolean isReleased = false;
	private MediaPlayer mediaPlayer = null;

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// s声明一个mp3Info,返回一个扩展数据的序列化意图
		Mp3Info mp3Info = (Mp3Info) intent.getSerializableExtra("mp3Info");
		int MSG = intent.getIntExtra("MSG", 0);
		if (mp3Info != null) {
			if (MSG == PLAY_MSG) {
				// 调用播放的方法
				play(mp3Info);
			}
		} else {
			if (MSG == PAUSE_MSG) {
				// 调用暂停的方法
				pause();
			} else if (MSG == STOP_MSG) {
				// 调用停止的方法
				stop();
			}
		}
		return super.onStartCommand(intent, flags, startId);
	}

	private void play(Mp3Info mp3Info) {

		String path = getMp3Path(mp3Info);
		// 得到播放创建的歌曲文件路径
		mediaPlayer = MediaPlayer.create(this, Uri.parse("file://" + path));
		// 不设置循环播放
		mediaPlayer.setLooping(false);
		mediaPlayer.start();
		isPlaying = true;
		isReleased = false;

	}

	private void pause() {
		// 如过mediaPlayer存在,且正在播放,并且没有被回收,且没有被暂停,就可以暂停,
		if (mediaPlayer != null) {
			if (!isReleased) {
				if (!isPause) {
					mediaPlayer.pause();
					isPause = true;
					isPlaying = true;
				} else {
					mediaPlayer.start();
					isPause = false;
				}
			}
		}
	}

	// 停止
	private void stop() {
		// 如过mediaPlayer存在,且正在播放,并且没有被回收,就可以停止,释放歌曲
		if (mediaPlayer != null) {
			if (isPlaying) {
				if (!isReleased) {
					mediaPlayer.stop();
					mediaPlayer.release();
					isReleased = true;
				}
				isPlaying = false;
			}
		}
	}

	// 得到MP3 的路径
	private String getMp3Path(Mp3Info mp3Info) {
		// 得到SD卡的绝对路径
		String SDCardRoot = Environment.getExternalStorageDirectory()
				.getAbsolutePath();
		// 得到文件名
		String path = SDCardRoot + File.separator + "mp3" + File.separator
				+ mp3Info.getMp3Name();
		return path;
	}
}


19.亲,组织这些东西好累啊!但是别忘了最重要的权限和Activity和service的注册哦!!!

 

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.wang.Activity" android:versionCode="1" android:versionName="1.0">
	<application android:icon="@drawable/icon" android:label="@string/app_name">
		<activity android:name=".startAnimation" android:label="@string/app_name">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<activity android:name=".MainActivity" android:label="@string/app_name"/>
		<activity android:name=".Mp3ListActivity" android:label="@string/app_name"/>
		<activity android:name=".LocalMp3ListActivity" android:label="@string/app_name"/>
		<activity android:name=".PlayerActivity" android:label="@string/app_name"/>
		<service android:name="com.wang.service.DownloadService"></service>
		<service android:name="com.wang.service.PlayerService"></service>
	</application>
	<uses-sdk android:minSdkVersion="10" />
	<uses-permission android:name="android.permission.INTERNET" />
	<!-- 访问SD卡的权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
</manifest> 


20.嘿嘿,如果你能把这写代码看完,证明你是个想学习的孩子,好吧,那就共享一下运行结果:第一个是3s的欢迎界面,第二个是网络歌曲的图片,第三个是本地SD卡中的歌曲图片,第四个点击播放按钮时候,同步显示歌词的图片

 

21.源码链接地址:http://download.csdn.net/detail/wjky2014/4441676

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

如有侵权,请联系小编,小编对此深感抱歉,届时小编会删除文章,立即停止侵权行为,请您多多包涵。

既然都看到这里,领两个红包在走吧!
以下两个红包每天都可以领取

1.支付宝搜索 522398497,或扫码支付宝红包海报。

支付宝扫一扫,每天领取大红包

2.微信红包,微信扫一扫即可领取红包

 

微信扫一扫,每天领取微信红包

小礼物走一走,来简书关注我

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值