【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 ...
随机推荐
- django orm 时间处理
说明 datetime 类型赋值: 数据库设置时区为:utc 系统设置时区为:'Asia/Shanghai' 1.赋值为:‘2019-04-24 15:00:00’ 数据库的结果为 ‘ ...
- 紫书 例题 10-17 UVa 1639(数学期望+分数处理+处理溢出)
设当前有k个,那么也就是说拿到其他图案的可能是(n-k)/n 那么要拿到一个就要拿n/(n-k)次 所以答案就是n(1/n + 1/(n-1) ......1/2 + 1 / 1) 看起来很简单,但是 ...
- 紫书 例题 10-15 UVa 1638(递推)
从大到小安排杆子 分三种情况 (1)插到最左边,那么左边看到了杆子会多一个 (2)插到最右边,那么右边看到了杆子会多一个 (3)插到中间边,那么不影响左边和右边看到的杆子数 具体看代码 #includ ...
- hadoop MR 任务 报错 "Error: java.io.IOException: Premature EOF from inputStream at org.apache.hadoop.io"
错误原文分析 文件操作超租期,实际上就是data stream操作过程中文件被删掉了.一般是由于Mapred多个task操作同一个文件.一个task完毕后删掉文件导致. 这个错误跟dfs.datano ...
- 【JavaScript】分秒倒计时器
一.基本目标 在JavaScript设计一个分秒倒计时器,一旦时间完毕使button变成不可点击状态 详细效果例如以下图.为了说明问题.调成每50毫秒也就是每0.05跳一次表, 真正使用的时候,把wi ...
- C++对象模型——效率有了,弹性呢(第七章)
7.4 效率有了,弹性呢 传统的C++对象模型提供有效率的运行期支持.这份效率,再加上与C之间的兼容性,造成了C++的广泛被接受度.然而,在某些领域方面,像是动态共享函数库(dynamicall ...
- Codeforces Round #105 (Div. 2) 148C Terse princess(脑洞)
C. Terse princess time limit per test 1 second memory limit per test 256 megabytes input standard in ...
- HDU 5389 Zero Escape(DP + 滚动数组)
Zero Escape Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) To ...
- OpenCV【2】---读取png图片显示到QT label上的问题
问题一: 操作图片test.png是一个365x365的PNG图片 通过OpenCV自带的GUI显示出来图像是没问题的,例如以下操作代码所看到的: QStringfileName=QFileD ...
- CSS 相对/绝对(relative/absolute)定位与jQuery的控制显示隐藏
曾经写显示隐藏老是用jq方法控制: dom.show(); dom.hide(); 事实上这样还是有非常多缺陷的. 这是html结构: <div class="holi"&g ...