zoukankan      html  css  js  c++  java
  • 5.1.4 用于音频的MediaStore

        本书前面讨论了如何将MediaStore用于图像。我们所学过的大多数只是都可用来存储和检索其他类型的媒体,包括音频。为了提供可靠的机制用于浏览和搜索音频,Android包括一个MediaStore.Audio程序包,其中定义了标准的内容提供器。

        1.通过MediaStore访问音频

        使用MediaStore提供器访问存储的音频文件与之前使用MediaStore的方式相似。在当前情况下,将使用android.provider.MediaStore.Audio程序包。

        演示活动将MediaStore用于音频的最简单方式是给出一个示例应用程序。以下代码创建一个活动,其查询MediaStore以获得任何音频文件,并简单的播放返回的第一个文件。

     1 package com.nthm.androidtest;
     2 
     3 import java.io.File;
     4 import android.app.Activity;
     5 import android.content.Intent;
     6 import android.database.Cursor;
     7 import android.net.Uri;
     8 import android.os.Bundle;
     9 import android.os.Environment;
    10 import android.provider.MediaStore;
    11 import android.view.View;
    12 import android.view.View.OnClickListener;
    13 import android.widget.Button;
    14 
    15 public class AudioPlayer extends Activity implements OnClickListener {
    16     private Button playButton;
    17     private String []columns={MediaStore.Audio.Media.DATA,
    18             MediaStore.Audio.Media._ID,
    19             MediaStore.Audio.Media.TITLE,
    20             MediaStore.Audio.Media.DISPLAY_NAME,
    21             MediaStore.Audio.Media.MIME_TYPE,
    22             MediaStore.Audio.Media.ARTIST,
    23             MediaStore.Audio.Media.ALBUM,
    24             MediaStore.Audio.Media.IS_RINGTONE,
    25             MediaStore.Audio.Media.IS_ALARM,
    26             MediaStore.Audio.Media.IS_MUSIC,
    27             MediaStore.Audio.Media.IS_NOTIFICATION};
    28     @Override
    29     protected void onCreate(Bundle savedInstanceState) {
    30         super.onCreate(savedInstanceState);
    31         setContentView(R.layout.audioplayer);

         为了使用MediaStore,需要指定想要返回的数据。可以通过使用在android.provider.MediaStore.Audio.Media类中定义的常量创建一个字符串数组来实现该操作。这些常量都是保存在MediaStore中以用于音频的标准字段。

        在当前情况下,正在请求DATA列,其中包含了实际的音频文件路径。还将请求内部ID、标题(Title)、显示名称(Display Name)、MIME类型(MIME-Type)、艺术家(Artist)、唱片集(Album)以及它是哪种类型的音频文件(包括警报、音乐、铃声或通知类型)。

       其他列(如添加时间(DATA_ADDED)、修改日期(DATE_MODIFIED)、文件大小(SIZE)等)也同样可用。

       通过调用活动中的managedQuery方法来查询MediaStore。managedQuery方法接受内容提供器的Uri作为参数。在当前情况下,该内容提供器是音频MediaStore,对应的Uri是android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI。这个Uri指定我们想要存储在SD卡上的音频。如果想要存储在内存中的音频文件,那么将使用android.provider.MediaStore.Audio.Media.INXTERNAL_CONTENT_URI。

       除了指向MediaStore的Uri,managedQuery方法还接受想返回的列数组,一条SQL WHERE子句,用于WHERE子句的值以及一条SQL ORDER BY子句。

       这个示例不会使用WHERE和ORDER BY子句,所以对于这些参数会传入null。

    1    Cursor cursor=managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, columns, null, null, null);

         managedQuery方法返回一个Cursor对象。Cursor类允许我们与从数据库查询返回的数据集交互。

         要做的第一件事实创建几个变量,以保存一些想要从结果中访问的列的编号。这不是绝对必须的,但是获得索引将会非常的方便,从而不必在每次需要他们的时候调用Cursor对象上的方法。获得他们的方法是将想要的类的常量值传递给Cursor对象上的getColumnIndex方法。

    1 int fileColumn=cursor.getColumnIndex(MediaStore.Audio.Media.DATA);

       第一个索引是包含指向实际音频文件的路径的列索引。通过传入表示该列的常量android.provider.MediaStore.Audio.Media.DATA,可以获得上述索引。

       接下来将获得几个其他的索引,他们并非都是实际正在使用的列,这里仅仅是为了演示目的而获得他们。

    1         int titleColumn=cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
    2         int displayColumn=cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME);
    3         int mimeTypeColumn=cursor.getColumnIndex(MediaStore.Audio.Media.MIME_TYPE);

       由MediaStore返回的数据在Cursor对象中可用,且通过行以及列的方式组织起来。通过调用moveToFirst方法和检索它的结果,可以获得返回的第一个结果。如果没有返回任何行,那么该方法将返回一个布尔值false,所以可以将它包含在一条if语句中以确保存在数据。

    1 if(cursor.moveToFirst()){

        为了获得实际的数据,可以调用Cursor上的“get”方法之一,并传入希望检索的类索引。如果数据预期是一个字符串,那么就调用getStirng。如果数据预期是一个整数,那么调用getInt。对于所有的基本数据类型,都有一个合适的“get”方法。

    1             String audioFilePath=cursor.getString(fileColumn);
    2             String mimeType=cursor.getString(mimeTypeColumn);

        一旦获得了文件的路径和MIME类型,就可以使用它们构造意图,以启动内置的音频播放器的应用程序,并播放文件(或者可以使用之前演示的MediaPlayer类直接播放音频文件)。为了将音频文件的路径转换成可以传递到意图的Uri,可以构造一个File对象并用Uri.fromFile方法来获取Uri。还有其他方法可用来完成同样的事情,但这可能是最简单的方法。

    1             Intent intent=new Intent(android.content.Intent.ACTION_VIEW);
    2             File newFile=new File(audioFilePath);
    3             intent.setDataAndType(Uri.fromFile(newFile), mimeType);
    4             startActivity(intent);
    5         }
    6        }
    7     }

        以上就完成了如何将MediaStore用于音频的基本说明。

       现在让我们更深入一步,创建一个应用程序,从中可以缩小返回的结果,并对他们进行浏览,从而允许用户选择音频文件进行播放。

       2.浏览MediaStore中的音频

       音频文件(特别是音乐文件)可以按照唱片集、艺术家和流派(Genre)来查找,也可以直接在MediaStore中查找。每个音频文件都有一个Uri,可以使用managedQuery来搜索。

       唱片集:android.provider.MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI

       艺术家:android.provider.MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI

       流派:android.provider.MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI

       一下代码演示了如何使用唱片集Uri来查询设备上的所有唱片集:

    1         String [] columns={android.provider.MediaStore.Audio.Albums._ID,
    2                 android.provider.MediaStore.Audio.Albums.ALBUM};
    3         Cursor cursor=managedQuery(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, columns, null, null, null);
    4         if(cursor!=null){
    5             while(cursor.moveToNext()){
    6                 cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM));
    7             }
    8         }

        在上述代码中,可以看到其请MediaStore返回_IDALBUM列。ALBUM常量表明我们希望返回该唱片集的名称。其他可用的列在android.provider.MediaStore.Audio.Albums类中列出,且都继承自android.provider.BaseColumns和android.provider.MediaStore.Audio.AlbumColumns。

       仅仅给定Uri和列的类表来调用managedQuery方法,而使其他的参数为null。这将返回设备上所有可用的唱片集。

       最后输出唱片集列表。为了对位于Cursor对象内部的返回列表进行遍历,首先检查该Cursor对象是否包含结果(cursor!=null),然后使用cursor.moveToNext()方法。

       3.唱片集浏览应用程序示例

       下面是一个示例,其使用上述内容作为一个起点,允许用户查看所有唱片集的名称。用户可以指定他或她想查看哪个唱片集上的歌曲。然后,它将列出歌曲列表,如果用户选择了其中一首,那么它将播放这首歌曲。

     1 package com.nthm.androidtest;
     2 
     3 import java.io.File;
     4 import android.app.ListActivity;
     5 import android.content.Intent;
     6 import android.database.Cursor;
     7 import android.net.Uri;
     8 import android.os.Bundle;
     9 import android.provider.MediaStore;
    10 import android.view.View;
    11 import android.widget.ListView;
    12 import android.widget.SimpleCursorAdapter;

         没有扩展一个通用的活动,我们将扩展ListActivity,从而能够展现和管理一个基本的ListView对象。

    1 public class AudioBrowser extends ListActivity {
    2     private Cursor cursor;

         接下来将创建几个常量,他们将帮助跟踪用户在应用程序中的位置,而且在用户执行动作时做出适当的响应。以下代码将在currentState变量中跟踪用户,该变量起始位置设置为STATE_SELECT_ALBUM。

    1     public static int STATE_SELECT_ALBUM=0;
    2     public static int STATE_SELECT_SONG=1;
    3     private int currentState=STATE_SELECT_ALBUM;

        就像普通的活动一样,其中有一个onCreate方法用来执行初始命令。

    1     @Override
    2     protected void onCreate(Bundle savedInstanceState) {
    3         super.onCreate(savedInstanceState);
    4         setContentView(R.layout.audiobrowser);

        在设置完布局之后(通过audiobrowser.xml布局XML文件),创建一个字符串数组,标志当运行查询时将从MediaStore返回的列。在这种情况下,它与上述代码片段相同——我们想要返回_ID和唱片集的名称,即ALBUM。他们都是在MediaStore.Audio.Albums类中列出的常量。

    1         String[] columns={android.provider.MediaStore.Audio.Albums._ID,
    2                           android.provider.MediaStore.Audio.Albums.ALBUM};

        仅仅用表示唱片集的Uri以及列的列表来调用managedQuery方法,其他参数都设为null,这应该会返回一个所有可用唱片集的列表。

    1         cursor=managedQuery(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, columns, null, null, null);

        一旦这么操作,就会返回一个包含查询结果的Cursor对象。

        由于使用了ListActivity,因此能够使它自动管理数据列表。可以使用setListAdapter犯法将Cursor对象绑定到ListView对象。

        首先创建一个字符串数组,他们表示想要显示的Cursor对象中的列名。在当前的情况下,我们只想要唱片集、的名称。即MediaStore.Audio.Albums.ALBUM使对应的常量。

        接下来,列出将用来显示来自这些列的数据的View对象。由于现在只有一列,因此,只需要一个View对象,即android.R.id.text1。这个View对象是可用的,因为他是下一步将要使用的android.R.layout.simple_list_item_1布局的一部分。

       最后调用setListAdapter方法,并传入一个内部创建的SimpleCursorAdapter。SimpleCursorAdapter是一个简单的适配器,它将Cursor对象包含的数据转换给ListActivity。在创建SimpleCursorAdapter时,传入作为上下文的活动(this)、一个已经定义的标准ListView布局(android.R.layout.simple_list_item_1)、包含数据的Cursor对象以及刚刚定义的两个数组。

    1         String []displayFields=new String[]{MediaStore.Audio.Albums.ALBUM};
    2         int [] displayerViews=new int[]{android.R.id.text1};
    3         setListAdapter(new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, displayFields, displayerViews));
    4     }

        如果运行这段代码,将获得设备上可用的唱片集的一个简单的类表。不过我们打算更深一步,允许用户选择一个唱片集。

        为了允许用户实际的选择一个唱片集,需要重写由父类ListActivity提供的默认方法onListItemClick。

    1     @Override
    2     protected void onListItemClick(ListView l, View v, int position, long id) {
    3         super.onListItemClick(l, v, position, id);
    4         if(currentState==STATE_SELECT_ALBUM){

        当选择类表中的的唱片集时将调用该方法。由于currentState变量开始时是STATE_SELECT_ALBUM,因此第一次调用该方法时,它应该为true。

        传入在列表中选定的唱片集位置,同时Cursor对象将利用该位置,通过调用moveToPosition方法获知它是哪个唱片集。

    1            if(cursor.moveToPosition(position)){

        假定moveToPosition方法成功返回,我们将重新开始查询MediaStore。然而,由于这一次想要访问单个媒体文件,因此是在MediaStore.Audio.Media.EXTERNAL_CONTENT_URI上运行managedQuery方法。

        首先选择想要返回的列。

    1                 String [] columns={MediaStore.Audio.Media.DATA,
    2                         MediaStore.Audio.Media._ID,
    3                         MediaStore.Audio.Media.TITLE,
    4                         MediaStore.Audio.Media.DISPLAY_NAME,
    5                         MediaStore.Audio.Media.MIME_TYPE};

        接下来需要为查询构造SQL WHERE 子句。因为我们只想选择属于特定唱片集的媒体文件,所以应在WHERE子句中指明这一点。

        普通SQL中的WHERE子句如下表示:

        WHERE album=‘album name’

        由于正在使用managedQuery,因此不需要WHERE关键字,同时也不需要传入它的等价物。相反,我们采用一个“?”符号进行替代。因此对于上述版本,该字符串将如下所示:

        album=?

        由于正在使用常量,并不知道列的实际名称,因此将使用该常量来构造WHERE子句。

    1          String where=android.provider.MediaStore.Audio.Media.ALBUM+"=?";

    为了完成WHERE子句,需要数据来替换WHERE子句中的“?”符号。这将是一个字符串数组,其中的每个字符串对应一个使用的“?”符号。在当前情况下,我们需要使用选择的唱片集名称。因为Cursor对象位于正确的位置,所以只需要对正确的列调用Cursor对象上的getString方法,可以通过对列名调用Cursor对象上的getColumnIndex方法来获得正确的列。

    1         String whereVal[]={cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM))};

        然后可以指定我们希望以特定列的值对结果进行排序。为此,需要创建一个变量,其包含了希望结果按其顺序排列的列名。

    1        String orderBy=android.provider.MediaStore.Audio.Media.TITLE;

        最后,运行managedQuery方法,传入Uri、列、WHERE子句的变量、WHERE子句的数据以及ORDER BY 子句的变量。

    1        cursor=managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, columns, where, whereVal, orderBy);

        同样,将使用ListActivity的各种方法来管理Cursor对象和展示列表中的结果。

    1                 String []displayFields=new String[]{MediaStore.Audio.Media.DISPLAY_NAME};
    2                 int [] displayerViews=new int[]{android.R.id.text1};
    3                 setListAdapter(new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, displayFields, displayerViews));

        最后要做的事情是将currentState变量改为STATE_SELECT_SONG,从而当下一次调用该方法时,我们将跳过所有这些步骤,因为用户将选定一首歌而不是唱片集。

    1                currentState=STATE_SELECT_SONG;
    2             }
    3         }else if(currentState==STATE_SELECT_SONG){

        当用户选择唱片集并从列表中选定一首歌时,他或她将进入该方法的这部分,因为currentState将等于STATE_SELECT_SONG

    1               if(cursor.moveToPosition(position)){

        正如前面所做的那样,调用Cursor对象上相同的moveToPosition方法,我们可以获得实际选择的这首歌。在这种情况下,我们会获得包含文件路径的列以及该文件的MIME类型。我们将它转换成一个File对象,并创建一个意图以启动内置的音乐播放器应用程序。

     1                 int fileColumn=cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
     2                 int mimeTypeColumn=cursor.getColumnIndex(MediaStore.Audio.Media.MIME_TYPE);
     3                 String audioFilePath=cursor.getString(fileColumn);
     4                 String mimeType=cursor.getString(mimeTypeColumn);
     5                 Intent intent=new Intent(android.content.Intent.ACTION_VIEW);
     6                 File file=new File(audioFilePath);
     7                 intent.setDataAndType(Uri.fromFile(file), mimeType);
     8                 startActivity(intent);
     9             }
    10         }
    11     }
    12 }

        下面是用于上述代码的布局XML文件,你将注意到它包含了一个ID为list的ListView对象。这是用于我们正在扩展的ListActivity的默认的ID。

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     android:layout_width="match_parent"
     3     android:layout_height="match_parent"
     4     android:orientation="vertical"
     5     >
     6  <ListView 
     7      android:id="@+android:id/list"
     8      android:layout_width="wrap_content"
     9      android:layout_height="wrap_content"></ListView>
    10 </LinearLayout>

         现在就完成了该示例应用程序,它使得我们能够通过使用MediaStore浏览唱片集,并选择歌曲进行播放。以可以使用非常类似的方法来构建应用程序,从而能够基于艺术家和流派来浏览和选择音乐。

  • 相关阅读:
    dataGridView 滚动条 同步
    TextBox 只读
    grid 数据绑定后
    iframe 跳转问题
    TextBox 不可编辑
    C# 添加Excel 批注、如何在Excel的单元格里面增加批注
    dataSet 比较
    sql 游标、sql server 游标使用、实例
    Tab键
    计算文本框的字算、计算TextBox的字数长度
  • 原文地址:https://www.cnblogs.com/ZSS-Android/p/3939859.html
Copyright © 2011-2022 走看看