• 【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、首先在resvaluesstrings.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】日期拾取器、时间拾取器与菜单》(点击打开链接)一样。对resmenumain.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、之后,改动reslayoutactivity_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界面为resmenumenu.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卡的媒体信息,我才省悟无须迭代这么麻烦。

  • 相关阅读:
    Golang 版本 支付宝支付SDK app支付接口2.0
    用 Certbot-auto 在 letsencrypt.org申请免费 SSL 证书实现 HTTPS
    Go类型断言demo
    签名算法
    golang cron定时任务简单实现
    Chapter Zero 0.2.2 内存
    Linux-系统目录结构
    Linux-关于Bash
    Chapter Zero 0.2.1 执行运算与判断的CPU
    Chapter Zero 0.1.4 计算机上常用的计算单位
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7088033.html
Copyright © 2020-2023  润新知