1.首先看看实现MP3播放器的功能的布局文件
1.欢迎界面的布局startimage.xml
<?xml version="1.0" encoding="utf-8"?>2.网络歌曲和本地歌曲的布局的主布局main.xml
<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>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"3.网络歌曲的布局intent_mp3_list.xml
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>
<?xml version="1.0" encoding="utf-8"?>4,本地歌曲列表的布局local_mp3_list.xml
<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>
<?xml version="1.0" encoding="utf-8"?>5.是音乐播放界面的布局player.xml
<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>
<?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;8.动画结束后就回跳转到下一个界面mainActivity.java
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);
}
});
}
}
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;10.接着是本地歌曲的实现代码LocalMp3ListActivity.java
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);
}
}
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);
}
}
}
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;13.xml解析的实现过程之Mp3ListContentHandler.java
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;
}
}
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;16.关于歌词播放的实现功能LrcProcessor.java
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;
}
}
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卡中的歌曲图片,第四个点击播放按钮时候,同步显示歌词的图片