说明:之前移植了Qt,也设置了环境变量,然后运行Qt程序,出现程序界面,但是对于鼠标点击,Qt界面花屏,出现系统背景,绿色等相关信息失望至极,现在我们就来做Qt移植。
一、介绍:PC系统:ubuntu10.04LTS
kernel: 2.6.32
交叉编译器:arm-none-linux-gnueabi-gcc 4.3.3 (arm-2009q1-203)
目标板:DM3730(处理器:Crotex A8)
1、编译好的qt4.7.3移植库;
2、编译好的Qt Mobility;(暂未使用);
3、编译好的tslib;
三、Qt移植: 1、拷贝库文件package com.test;
/**
* 橡皮类
* */
public abstract class Eraser {
public abstract void erase();
}
package com.test;
/**
* 铅笔类
* */
public abstract class Pencil {
public abstract void wirte();
}
package com.test;
/**
* 做一个既有铅笔功能又有橡皮擦功能类
* (用接口完全可以实现,这里只是假设这种情况,模拟多继承)
* */
public class PencilWithEraser{
private MyPencil pencil = new MyPencil();
private MyEraser eraser = new MyEraser();
/**
*
* 继承了铅笔的功能
*
* */
private class MyPencil extends Pencil{
@Override
public void wirte() {
System.out.println("use to wirte");
}
}
/*写一个既有笔功能又有橡皮侧功能的类
**/
private class MyEraser extends Eraser {
@Override
public void erase() {
System.out.println("use to erase");
}
}
/*
* 本类自己的方法
* */
public void wirte(){
pencil.wirte();
}
public void eraser(){
eraser.erase();
}
}
测试类
package com.test;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
PencilWithEraser pencilWithEraser = new PencilWithEraser();
pencilWithEraser.wirte();
pencilWithEraser.eraser();
}
}
这个类既有笔又有橡皮擦功能了。模拟实现了Java多继承。
暑假第二十九天,感觉最近好晕,学的东西好少,博客也更新好慢,今天终于有可以更新一下下,我承认程序员真的很累很累!!每天对着电脑瞧着代码,想着创意,考虑着UI和用户体验,哎!!抱怨下,我们悲催的程序员们!!抱怨归抱怨,既然选择了这条路我们还是的走下去滴,好了,抱怨结束,看看这个MP3的功能是什么,首先是3s钟的欢迎界面,然后是可以从网络上下载歌曲的界面,接着是本地手机SD卡歌曲列表的界面,点击本地歌曲的列表,进入歌曲播放的界面,歌曲播放界面可以实现歌曲的播放和歌词的同步显示功能!!功能就这么多,有点少,其实自己还有一点小想法,不过还没实现,等着以后慢慢在实现,好了,废话也就不多说了,看看功能实现的过程吧!!
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="/blog_article/@drawable/hello/index.html" > </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="/blog_article/@drawable/images/index.html" /> <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="/blog_article/@drawable/pause/index.html" /> <ImageButton android:id="@+id/begin" android:paddingLeft="10dip" android:layout_width="80dp" android:layout_height="80dp" android:src="/blog_article/@drawable/begin/index.html" /> <ImageButton android:id="@+id/stop" android:paddingLeft="10dip" android:layout_width="80dp" android:layout_height="80dp" android:src="/blog_article/@drawable/stop/index.html" /> </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); } } }
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(/blog_article/urlStr/index.html); // 创建一个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(/blog_article/String urlStr/index.html) throws MalformedURLException, IOException { // 声明一个URL对象 url = new URL(/blog_article/urlStr/index.html); // /打开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