【Android】利用安卓的数据接口、多媒体处理编写内存卡Mp3播放器app
通过调用安卓的MediaPlayer能够直接完毕Mp3等主流音频的播放,同一时候利用ContentResolver与Cursor能够直接读取安卓内在数据库的信息。直接获取当前sdcard中全部音频的列表,无须像《【Android】内存卡图片读取器。图库app》(点击打开链接)一样利用原始的Java代码去遍历整个sdcard卡,直接调用安卓固有的类既便捷又高速。最后。读取出来的Mp3能够通过适配器直接载入到ListView列表,做出例如以下所看到的的内存卡Mp3播放器app效果。本app在自己的真实的16G内存卡上真机測试通过。
首先,如果在内存卡上有例如以下的5个mp3文件,这里顺带提一句。利用DDMS复制文件到内存卡的时候注意,亲測发现,无法送PC上一个中文命名的文件到安卓虚拟机AVD。仅仅能送英文文件。不嫌麻烦,能够先改名再传输,到安卓虚拟机AVD再改名。或者直接用英文歌曲。
DDMS的使用能够參考《【Android】把外部文件拷贝的AVD安卓模拟器上的sdcard上。而且在AVD中浏览sdcard的文件》(点击打开链接)。
之后。例如以下图所看到的,实现一个mp3播放器的大致功能,能够调节音量,上一首、下一首、播放等等。在没有选定音乐这些button禁用。
制作步骤例如以下:
1、首先在res\values\strings.xml设置各个button与菜单的字体例如以下:
<?xml version="1.0" encoding="utf-8"?>
<resources> <string name="app_name">内存卡mp3播放器</string>
<string name="action_settings">Settings</string>
<string name="button1">上一首</string>
<string name="button2">暂停</string>
<string name="button3">停止</string>
<string name="button4">下一首</string>
<string name="menu_author">作者:yongh701</string>
<string name="menu_exit">退出</string> </resources>
2、其次,如《【Android】日期拾取器、时间拾取器与菜单》(点击打开链接)一样。对res\menu\main.xml进行改动,设定一个非常easy的菜单:
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item
android:id="@+id/menu_exit"
android:title="@string/menu_exit"/>
<item android:title="@string/menu_author"/> </menu>
3、然后,因为设置sdcard的操作与改变系统的媒体音量,须要到AndroidManifest.xml申请权限,此文件改动之后例如以下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mp3player"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 要求向SDCard读取数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 要求向SDCard写入数据权限 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!-- 要求改变音量的权限 --> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.mp3player.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>
4、之后,改动res\layout\activity_main.xml对MainActivity.java进行布局。
思想例如以下图:
在一个自上而下垂直的线性布局下,摆两个横向的水平线性布局与一个列表视图ListView,宽度皆匹配父布局。当中。第一个横向的水平线性布局通过《【Android】利用相对布局布置更新软件的style为主题对话框的Activity,利用layout_weight属性对表格布局的行划分》(点击打开链接)提及到的方式,等分放置四个button,其次,在第二个横向的水平线性布局,放置一个仅包裹内容的。用于文字显示音量的TextView与一个进度条SeekBar。这两个横向的水平线性布局的高度都是仅包裹内容就可以。最后的ListView的高度直接匹配父布局。因此,代码例如以下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <Button
android:id="@+id/button1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/button1" /> <Button
android:id="@+id/button2"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/button2" /> <Button
android:id="@+id/button3"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/button3" /> <Button
android:id="@+id/button4"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/button4" /> </LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> <SeekBar
android:id="@+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout> <ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView> </LinearLayout>
5、最后,是本app实现的核心,对MainActivity.java进行编写。大体上分为三部分:各个组件的代码实现、菜单的实现与返回按键的监听。之所以对返回物理button的监听。是由于须要要求。用户在按返回物理button是彻底退出程序。退出程序时候。还要释放被本app占用系统的MediaPlayer,因此还要重写onDestory方法。释放资源。
否则在程序退出之后,播放的音乐依旧会“绕梁三日”。
在组件代码实现的部分。还有例如以下细分。注冊各个组件之后。能够直接利用ContentResolver contentResolver = getContentResolver();获取安卓系统的数据接口,这个数据接口是安卓系统内部的数据库。里面存放着几张记录当前系统全部媒体,类似图片、音乐、视频等信息的表,通过Cursor这个数据库的迭代器。或者叫游标,反正是iterator对表进行遍历,能够直接取出媒体的信息。这里取走最关键的信息,无须用Java原始的遍历方法《【Java】读取其下全部目录与文件的路径》(点击打开链接),迭代求出各个音乐媒体的路径,产生巨大的时间复杂度。
package com.mp3player; import java.util.ArrayList;
import java.util.Collections; import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.provider.MediaStore;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast; public class MainActivity extends Activity {
private MediaPlayer mediaPlayer = new MediaPlayer();
private ListView listView1;
private ArrayList<String> audioList;// 存放音乐路径的动态数组
private int currentAudioId;
private Button button1;
private Button button2;
private Button button3;
private Button button4;
private TextView textView1;
private SeekBar seekBar1; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注冊各个组件
listView1 = (ListView) findViewById(R.id.listView1);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button3 = (Button) findViewById(R.id.button3);
button4 = (Button) findViewById(R.id.button4);
textView1 = (TextView) findViewById(R.id.textView1);
seekBar1 = (SeekBar) findViewById(R.id.seekBar1);
// 初始状态“暂停/播放”按钮不可用,由于没有选定音乐
button1.setEnabled(false);
button2.setEnabled(false);
button3.setEnabled(false);
button4.setEnabled(false);
// 载入音乐资源
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
audioList = new ArrayList<String>();
for (cursor.moveToFirst(); !(cursor.isAfterLast()); cursor.moveToNext()) {
String path = cursor.getString(cursor
.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
audioList.add(path);
}
Collections.sort(audioList);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, audioList);
listView1.setAdapter(arrayAdapter);
listView1.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<? > arg0, View arg1,
int position, long arg3) {
currentAudioId = position;
String path = audioList.get(currentAudioId);
playMusic(path);
button1.setEnabled(true);
button3.setEnabled(true);
button4.setEnabled(true);
}
});
Toast.makeText(MainActivity.this,
"音乐载入完毕,共" + audioList.size() + "首音乐", Toast.LENGTH_SHORT)
.show();
// 调节音量的功能
final AudioManager audioManager = (AudioManager) MainActivity.this
.getSystemService(Context.AUDIO_SERVICE);// 音乐管理器必须使用final类在OnCreate中定义
MainActivity.this.setVolumeControlStream(AudioManager.STREAM_MUSIC);// 调节的是媒体音量
seekBar1.setMax(audioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC));// 设置音量条的最大值为系统媒体音量的最大值
int volume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);// 当前媒体音量
seekBar1.setProgress(volume);
textView1.setText("音量:" + volume);
seekBar1.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar arg0) {
} @Override
public void onStartTrackingTouch(SeekBar arg0) {
} @Override
public void onProgressChanged(SeekBar arg0, int progress,
boolean arg2) {
textView1.setText("音量:" + progress);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
progress, AudioManager.FLAG_PLAY_SOUND);// 设置改变之后的音量
}
});
// 各个按钮的点击监听
// 上一首
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
currentAudioId--;
if (currentAudioId < 0) {
currentAudioId = 0;
}
String path = audioList.get(currentAudioId);
playMusic(path);
}
});
// 暂停/播放按钮
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
button2.setText("继续");
} else {
mediaPlayer.start();
button2.setText("暂停");
}
}
});
// 停止按钮
button3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
button2.setEnabled(false);
button3.setEnabled(false);
}
});
// 下一首按钮
button4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
currentAudioId++;
if (currentAudioId > audioList.size() - 1) {
currentAudioId = audioList.size() - 1;
}
String path = audioList.get(currentAudioId);
playMusic(path);
}
});
} // 播放音乐
public void playMusic(String path) {
try {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.reset();
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}
button2.setEnabled(true);
button2.setText("暂停");
button3.setEnabled(true);
Toast.makeText(MainActivity.this, "播放:" + path + "", Toast.LENGTH_SHORT)
.show();
} // 退出程序时,释放当前音乐资源
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
} // 创建menu的方法,没有该方法,不会在右上角设置菜单。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// 设置menu界面为res\menu\menu.xml
getMenuInflater().inflate(R.menu.main, menu);
return true;
} // 处理菜单事件
public boolean onOptionsItemSelected(MenuItem item) {
// 得到当前选中的MenuItem的ID,
int item_id = item.getItemId();
switch (item_id) {
// 设置id为menu_exit的菜单子项所要运行的方法。 case R.id.menu_exit:
System.exit(0);// 结束程序
break;
}
return true;
} // 对物理按钮的监听
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
System.exit(0);
break;
}
return super.onKeyDown(keyCode, event);
}
}
之后。对于读取出来的文件信息。直接用适配器载入到ListView列表。
随后对各个按钮的监听没什么好说的,记得播放的音乐时要先释放当前正在播放的音乐再上新曲,安卓系统不会自己覆盖播放。这里还须要处理一个载入音乐失败的异常。
在音量处理部分,须要自己创建一个音乐管理器AudioManager,此管理器必须在OnCreate方法中以final的形式定义,否则会出现例如以下图的错误:
通过音乐管理器可以获取与改变当前系统的媒体音量。可以把这个音量值载入到进度条,进度条的使用在《【Android】进度条与线程之间的消息处理》(点击打开链接)中已经讲过,这里不再赘述。
我还上了一份源代码给大家:http://download.csdn.net/detail/yongh701/8932343。欢迎交流,上次感谢网友提醒能够通过安卓系统内部的数据库拿到sdcard卡的媒体信息,我才省悟无须迭代这么麻烦。
【Android】利用安卓的数据接口、多媒体处理编写内存卡Mp3播放器app的更多相关文章
- 安卓MP3播放器开发实例(1)之音乐列表界面
学习安卓开发有一年了,想想这一年的努力,确实也收获了不少.也找到了比較如意的工作. 今天准备分享一个以前在初学阶段练习的一个项目.通过这个项目我真正的找到了开发安卓软件的感觉,从此逐渐步入安卓开发的正 ...
- 安卓MP3播放器开发实例(3)之进度条和歌词更新的实现
上一次谈了音乐播放的实现,这次说下最复杂的进度条和歌词更新.因为须要在播放的Activity和播放的Service间进行交互,所以就涉及了Activity对Service的绑定以及绑定后数据的传输,这 ...
- Android利用Filter过滤数据
MainActivity如下: package cc.testfilterable; import java.util.ArrayList; import java.util.HashMap; imp ...
- [置顶] android利用jni调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so
0:前言 1:本文主要作为丙方android公司的身份来写 2:作者有不对的地方,请指出,谢谢 [第一篇:android利用jni调用第三方库——编写库libhello.so] [第二篇:androi ...
- Android学习笔记_24_多媒体MediaPlayer对象之音乐播放器与SoundPool声音池
一.MediaPlayer对象常用方法介绍: MediaPlayer mediaPlayer = new MediaPlayer(); if (mediaPlayer.isPlaying()) { m ...
- android开发之MediaPlayer+Service MP3播放器
import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Lis ...
- android之MP3播放器(1)
该播放器只是对本地的MP3文件进行简单的播放 布局文件 布局文件中设置了三个按钮分别来进行播放.暂停和继续播放 <?xml version="1.0" encoding=&q ...
- 从零开始学 Web 之 HTML5(四)拖拽接口,Web存储,自定义播放器
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- Android利用数据库传送数据
---恢复内容开始--- 一.建表 //通过SQLiteDatabase 创建数据库stu.db3 final SQLiteDatabase db = SQLiteDatabase.openOrCre ...
随机推荐
- HNU 12886 Cracking the Safe 二十四点的判断
经典的一个题,今天竟然写跪了…… 题意: 给你4个数字,让你判断是否能通过四则运算和括号,凑成24点. 思路: 暴力枚举运算顺序和运算符. 代码: #include <iostream> ...
- token登录验证机制
一张图解释 token登录验证机制
- vmware启动虚拟机报错VMware Workstation has paused this virtual machine because the disk on which the virtual machine is stored is almost full. To continue, free an additional 1.4 GB of disk space.
报错VMware Workstation has paused this virtual machine because the disk on which the virtual machine i ...
- docker安装cloudera manager,切换cloudera-scm用户报错can not open session
在root帐号下su - cloudera-scm报错can not open session 在网上搜,大概是说ulimit超过限制之类,搞了很久才找到/etc/security/limits.d/ ...
- jQuery模拟输出回车键
jQuery模拟输出回车键 学习了:https://zhidao.baidu.com/question/1753748968579760068.html 原文少了个r var e = jQuery.E ...
- poj 3261 后缀数组 找反复出现k次的子串(子串能够重叠)
题目:http://poj.org/problem?id=3261 仍然是后缀数组的典型应用----后缀数组+lcp+二分 做的蛮顺的,1A 可是大部分时间是在调试代码.由于模板的全局变量用混了,而自 ...
- javascript小白学习指南1---0
第二章 变量和作用域 在看第二章时我希望,你能够回想一下前一次所讲的内容 假设有所遗忘 点这里 今天我们来说说 变量和作用域的问题 本章主要内容 基本类型和引用类型 运行环境 垃圾回收( ...
- Java,泛型类型通配符和C#对照
c#的泛型没有类型通配符,原因是.net的泛型是CLR支持的泛型,而Java的JVM并不支持泛型,仅仅是语法糖,在编译器编译的时候都转换成object类型 类型通配符在java中表示的是泛型类型的父类 ...
- SSM框架之中如何进行文件的上传下载
SSM框架的整合请看我之前的博客:http://www.cnblogs.com/1314wamm/p/6834266.html 现在我们先看如何编写文件的上传下载:你先看你的pom.xml中是否有文件 ...
- Android的矩阵(一):ColorMatrix
最近的学习过程中看到关于android色彩矩阵的内容,以前看到这部分内容,基本都是跳过的,没有认真细读. 自己给自己找的借口是: 1,大一学的矩阵内容早就忘的干干净净了,当时学的时候就很烦人,所以现在 ...