我的 /raw 文件夹中有声音,我希望我的用户能够像 RingtonePreference 一样在首选项中选择一种声音,但仅限于我的声音。
4 回答
这是我的 RingtonePreference 替换。列出了所有系统铃声和您的自定义铃声(在 xml 中定义,存储在 res/raw 中):
ExtraRingtonePreference.java
package de.almisoft.test;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import de.almisoft.test.R;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.preference.DialogPreference;
import android.util.AttributeSet;
public class ExtraRingtonePreference extends DialogPreference {
private Context mContext;
private String mValue;
private Ringtone ringtone;
private int mRingtoneType;
private boolean mShowSilent;
private boolean mShowDefault;
private CharSequence[] mExtraRingtones;
private CharSequence[] mExtraRingtoneTitles;
public ExtraRingtonePreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExtraRingtonePreference, 0, 0);
mRingtoneType = a.getInt(R.styleable.ExtraRingtonePreference_ringtoneType, RingtoneManager.TYPE_RINGTONE);
mShowDefault = a.getBoolean(R.styleable.ExtraRingtonePreference_showDefault, true);
mShowSilent = a.getBoolean(R.styleable.ExtraRingtonePreference_showSilent, true);
mExtraRingtones = a.getTextArray(R.styleable.ExtraRingtonePreference_extraRingtones);
mExtraRingtoneTitles = a.getTextArray(R.styleable.ExtraRingtonePreference_extraRingtoneTitles);
a.recycle();
}
public ExtraRingtonePreference(Context context) {
this(context, null);
}
public String getValue() {
return mValue;
}
private Map<String, Uri> getSounds(int type) {
RingtoneManager ringtoneManager = new RingtoneManager(mContext);
ringtoneManager.setType(type);
Cursor cursor = ringtoneManager.getCursor();
Map<String, Uri> list = new TreeMap<String, Uri>();
while (cursor.moveToNext()) {
String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
Uri notificationUri = ringtoneManager.getRingtoneUri(cursor.getPosition());
list.put(notificationTitle, notificationUri);
}
return list;
}
private Uri uriFromRaw(String name) {
int resId = mContext.getResources().getIdentifier(name, "raw", mContext.getPackageName());
return Uri.parse("android.resource://" + mContext.getPackageName() + "/" + resId);
}
private String getExtraRingtoneTitle(CharSequence name) {
if (mExtraRingtones != null && mExtraRingtoneTitles != null) {
int index = Arrays.asList(mExtraRingtones).indexOf(name);
return mExtraRingtoneTitles[index].toString();
}
return null;
}
@Override
public CharSequence getSummary() {
String ringtoneTitle = null;
if (mValue != null) {
if (mValue.length() == 0)
ringtoneTitle = mContext.getString(R.string.silent);
if (ringtoneTitle == null && mExtraRingtones != null && mExtraRingtoneTitles != null) {
for (int i = 0; i < mExtraRingtones.length; i++) {
Uri uriExtra = uriFromRaw(mExtraRingtones[i].toString());
if (uriExtra.equals(Uri.parse(mValue))) {
ringtoneTitle = mExtraRingtoneTitles[i].toString();
break;
}
}
}
if (ringtoneTitle == null) {
Ringtone ringtone = RingtoneManager.getRingtone(mContext, Uri.parse(mValue));
String title = ringtone.getTitle(mContext);
if (title != null && title.length() > 0)
ringtoneTitle = title;
}
}
CharSequence summary = super.getSummary();
if (ringtoneTitle != null) {
if (summary != null)
return String.format(summary.toString(), ringtoneTitle);
else
return ringtoneTitle;
} else return summary;
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
final Map<String, Uri> sounds = new LinkedHashMap<String, Uri>();
if (mExtraRingtones != null) {
for (CharSequence extraRingtone : mExtraRingtones) {
Uri uri = uriFromRaw(extraRingtone.toString());
String title = getExtraRingtoneTitle(extraRingtone);
sounds.put(title, uri);
}
}
if (mShowDefault) {
Uri uriDefault = RingtoneManager.getDefaultUri(mRingtoneType);
if (uriDefault != null) {
Ringtone ringtoneDefault = RingtoneManager.getRingtone(mContext, uriDefault);
if (ringtoneDefault != null) {
sounds.put(ringtoneDefault.getTitle(mContext), uriDefault);
}
}
}
if (mShowSilent)
sounds.put(mContext.getString(R.string.silent), Uri.parse(""));
sounds.putAll(getSounds(RingtoneManager.TYPE_NOTIFICATION));
final String[] titleArray = sounds.keySet().toArray(new String[0]);
final Uri[] uriArray = sounds.values().toArray(new Uri[0]);
int index = mValue != null ? Arrays.asList(uriArray).indexOf(Uri.parse(mValue)) : -1;
builder.setSingleChoiceItems(titleArray, index, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (ringtone != null)
ringtone.stop();
String title = titleArray[which];
Uri uri = uriArray[which];
if (uri != null) {
if (uri.toString().length() > 0) {
ringtone = RingtoneManager.getRingtone(mContext, uri);
ringtone.play();
}
mValue = uri.toString();
} else mValue = null;
}
});
builder.setPositiveButton(R.string.ok, this);
builder.setNegativeButton(R.string.cancel, this);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (ringtone != null)
ringtone.stop();
if (positiveResult && callChangeListener(mValue)) {
persistString(mValue);
notifyChanged();
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue)
mValue = getPersistedString("");
else {
if (mExtraRingtones != null && defaultValue != null && defaultValue.toString().length() > 0) {
int index = Arrays.asList(mExtraRingtones).indexOf((CharSequence) defaultValue);
if (index >= 0)
mValue = uriFromRaw(defaultValue.toString()).toString();
else mValue = (String) defaultValue;
} else mValue = (String) defaultValue;
persistString(mValue);
}
}
}
资源/值/attrs.xml
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<declare-styleable name="ExtraRingtonePreference">
<attr name="ringtoneType">
<!-- Ringtones. -->
<flag name="ringtone" value="1" />
<!-- Notification sounds. -->
<flag name="notification" value="2" />
<!-- Alarm sounds. -->
<flag name="alarm" value="4" />
<!-- All available ringtone sounds. -->
<flag name="all" value="7" />
</attr>
<attr name="showSilent" format="boolean"/>
<attr name="showDefault" format="boolean"/>
<attr name="extraRingtones" format="reference"/>
<attr name="extraRingtoneTitles" format="reference"/>
</declare-styleable>
</resources>
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="silent">Silent</string>
<string name="ok">OK</string>
<string name="cancel">Cancel</string>
<string name="ringtoneTitle">Ringtone</string>
<string name="ringtoneSummary">Ringtone: %s</string>
<string-array name="extraRingtones">
<item>deichkind_sone_musik</item>
<item>madonna_like_a_virgin</item>
</string-array>
<string-array name="extraRingtoneTitles">
<item>Sone Musik</item>
<item>Like A Virgin</item>
</string-array>
</resources>
资源/原始
res
↳ raw
↳ deichkind_sone_musik.mp3
↳ madonna_like_a_virgin.mp3
res/xml/preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:auto="http://schemas.android.com/apk/res-auto">
<de.almisoft.test.ExtraRingtonePreference
android:key="ringtone"
android:title="@string/ringtoneTitle"
android:summary="@string/ringtoneSummary"
android:defaultValue="deichkind_sone_musik"
auto:ringtoneType="notification"
auto:showSilent="true"
auto:showDefault="true"
auto:extraRingtones="@array/extraRingtones"
auto:extraRingtoneTitles="@array/extraRingtoneTitles"/>
<!-- set android:defaultValue
to "deichkind_sone_musik" for your custom mp3
to "" for silent
to "content://settings/system/notification_sound" for system default ringtone -->
</PreferenceScreen>
所以最后我查看了 ListPreference 的源代码,并做了一些修改。由于我不能使用 com.android.internal.R.styleable.ListPreference 我必须在 attrs.xml 创建自己的样式:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ListPreference">
<attr name="entries" format="string"></attr>
<attr name="entryValues" format="string"></attr>
</declare-styleable>
<declare-styleable name="Preference">
<attr name="summary" format="string"></attr>
</declare-styleable>
</resources>
然后将其导入到我的preferences.xml 文件中,如下所示:
xmlns:foo="http://schemas.android.com/apk/res/com.abe.abemoto"
并使用它:
<com.abe.abemoto.preference.CustomSoundListPreference
android:defaultValue="@string/pref_alert_ring_value_1"
android:key="@string/pref_alert_sound_choice_for_notif_key"
android:title="Sonnerie de notification"
foo:entries="@array/pref_alert_ring_entries"
foo:entryValues="@array/pref_alert_ring_values"
foo:summary="Choisissez la sonnerie pour les notifications" />
在我的类 CustomSoundListPreference 中,我修改了 onPrepareDialogBuilder 方法以在单击的项目上播放我的声音。
@Override
protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
mMediaPlayer = new MediaPlayer();
if (mEntries == null || mEntryValues == null) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array.");
}
mClickedDialogEntryIndex = getValueIndex();
builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mClickedDialogEntryIndex = which;
String value = mEntryValues[which].toString();
Resources res = getContext().getResources();
int resId = res.getIdentifier(value, "raw",
getContext().getPackageName());
Uri uri = Uri.parse(String.format(getContext()
.getString(R.string.resource_sound),
getContext().getPackageName(), resId));
Log.d(TAG, "uri sound = " + uri);
try {
mMediaPlayer.reset();
mMediaPlayer.setDataSource(getContext(), uri);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
builder.setPositiveButton("Ok", this);
builder.setNegativeButton("Annuler", this);
}
这是自定义 ListPreference 的完整代码,就像铃声首选项一样:
import java.io.IOException;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.ListPreference;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
public class CustomListPreference extends ListPreference{
private MediaPlayer mMediaPlayer;
private Context mContext;
CharSequence[] mEntries;
CharSequence[] mEntryValues;
private int mClickedDialogEntryIndex;
private String mValue;
public CustomListPreference(Context context) {
super(context);
mContext = context;
}
/**
* Sets the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @param value The value to set for the key.
*/
public void setValue(String value) {
mValue = value;
persistString(value);
}
/**
* Sets the value to the given index from the entry values.
*
* @param index The index of the value to set.
*/
public void setValueIndex(int index) {
if (mEntryValues != null) {
setValue(mEntryValues[index].toString());
}
}
/**
* Returns the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @return The value of the key.
*/
public String getValue() {
return mValue;
}
/**
* Returns the entry corresponding to the current value.
*
* @return The entry corresponding to the current value, or null.
*/
public CharSequence getEntry() {
int index = getValueIndex();
return index >= 0 && mEntries != null ? mEntries[index] : null;
}
public int findIndexOfValue(String value) {
if (value != null && mEntryValues != null) {
for (int i = mEntryValues.length - 1; i >= 0; i--) {
if (mEntryValues[i].equals(value)) {
return i;
}
}
}
return -1;
}
private int getValueIndex() {
return findIndexOfValue(mValue);
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
mMediaPlayer = new MediaPlayer();
mEntries = getEntries();
mEntryValues = getEntryValues();
if (mEntries == null || mEntryValues == null) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array.");
}
mClickedDialogEntryIndex = getValueIndex();
builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mClickedDialogEntryIndex = which;
String value = mEntryValues[which].toString();
String path = findPathFromName(value);
try {
playSong(path);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
builder.setPositiveButton("Ok", this);
builder.setNegativeButton("Cancel", this);
}
private void playSong(String path) throws IllegalArgumentException,
IllegalStateException, IOException {
Log.d("ringtone", "playSong :: " + path);
mMediaPlayer.reset();
mMediaPlayer.setDataSource(path);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
// mMediaPlayer.setLooping(true);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
public String findPathFromName(String name) {
Cursor mCursor = getContext().getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
MediaStore.Audio.Media.TITLE + "='" + name + "'", null, null );
String path = "";
if(mCursor.moveToFirst()){
path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Media.DATA));
}
mCursor.close();
mCursor = null;
return path;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value);
}
private static class SavedState extends BaseSavedState {
String value;
public SavedState(Parcel source) {
super(source);
value = source.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(value);
}
public SavedState(Parcelable superState) {
super(superState);
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
String value = mEntryValues[mClickedDialogEntryIndex].toString();
if (callChangeListener(value)) {
setValue(value);
}
}
mMediaPlayer.stop();
mMediaPlayer.release();
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.value = getValue();
return myState;
}
}
希望这对某人有所帮助。
在进行铃声偏好自定义时,我更喜欢铃声只播放一小段时间,有点像样本声音。如果他们只是从列表中选择声音,用户不需要听到整个声音播放。这是我实现这一目标的方法:
首先创建一个将播放铃声的服务(使用铃声管理器播放声音而不是媒体播放器,因为它为我们处理取消):
公共类 PlayRingtoneService 扩展服务 { 静态铃声 r; 私有处理程序处理程序;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//activating alarm sound
if (r != null)
r.stop();
String filePath = intent.getStringExtra("uri");
r = RingtoneManager.getRingtone(this, Uri.parse(filePath));
r.play();
handler.removeCallbacksAndMessages(null);
handler.postDelayed(new Runnable() {
@Override
public void run() {
if(r!=null)
r.stop();
}
},6000L); //stop sound in 6 seconds
return super.onStartCommand(intent, flags, startId);
}
void setThreadPriority(int priority) {
try {
Process.setThreadPriority(priority);
} catch (Exception e) {
Timber.e(e);
}
}
@Override
public void onCreate() {
super.onCreate();
handler =new Handler();
setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
}
@Override
public void onDestroy() {
if (r != null)
r.stop();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
还使用服务更新清单:
<service android:name=".services.PlayRingtoneService" />
然后使用上面但修改的解决方案,您可以创建一个列表首选项,其行为就像铃声首选项:
public class CustomRingtoneListPreference extends ListPreference {
CharSequence[] mEntries;
CharSequence[] mEntryValues;
private int mClickedDialogEntryIndex;
private String mValue;
public CustomRingtoneListPreference(Context context) {
super(context);
}
public CustomRingtoneListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Returns the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @return The value of the key.
*/
public String getValue() {
return mValue;
}
/**
* Sets the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @param value The value to set for the key.
*/
public void setValue(String value) {
mValue = value;
persistString(value);
}
/**
* Returns the entry corresponding to the current value.
*
* @return The entry corresponding to the current value, or null.
*/
public CharSequence getEntry() {
int index = getValueIndex();
return index >= 0 && mEntries != null ? mEntries[index] : null;
}
public int findIndexOfValue(String value) {
if (value != null && mEntryValues != null) {
for (int i = mEntryValues.length - 1; i >= 0; i--) {
if (mEntryValues[i].equals(value)) {
return i;
}
}
}
return -1;
}
private int getValueIndex() {
return findIndexOfValue(mValue);
}
/**
* Sets the value to the given index from the entry values.
*
* @param index The index of the value to set.
*/
public void setValueIndex(int index) {
if (mEntryValues != null) {
setValue(mEntryValues[index].toString());
}
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
mEntries = getEntries();
mEntryValues = getEntryValues();
if (mEntries == null || mEntryValues == null) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array.");
}
mClickedDialogEntryIndex = getValueIndex();
builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mClickedDialogEntryIndex = which;
String value = mEntryValues[which].toString();
playSong(value);
}
});
builder.setPositiveButton("Ok", this);
builder.setNegativeButton("Cancel", this);
}
private void playSong(String path) {
Intent i = new Intent(getContext(), PlayRingtoneService.class);
i.putExtra("uri", path);
getContext().startService(i);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
String value = mEntryValues[mClickedDialogEntryIndex].toString();
if (callChangeListener(value)) {
setValue(value);
}
}
Intent i = new Intent(getContext(), PlayRingtoneService.class);
getContext().stopService(i);
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.value = getValue();
return myState;
}
private static class SavedState extends BaseSavedState {
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
String value;
public SavedState(Parcel source) {
super(source);
value = source.readString();
}
public SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(value);
}
}
}
现在在你的 xml 中像这样使用它:
<mypackage.blah.blah.CustomRingtoneListPreference
android:key="myRingtone"
android:title="my title"
android:summary="ringtone chosen %s"
android:defaultValue="0"
android:dependency="whatever you have"
/>
现在要将值实际加载到列表中,我们创建一个 utils 方法,该方法可以获取所有内部和外部媒体,并将其放入我们的模型类中,称为歌曲,定义如下:
public class Song {
private long id;
private Uri filePath;
private boolean externalPath;
/**
* Creates a new Song, with specified `songID` and `filePath`.
*
* @note It's a unique Android identifier for a media file
* anywhere on the system.
*/
public Song(long id, String title, String artist, Uri fileUri, boolean externalPath) {
this.id = id;
this.title = title;
this.artist = artist;
this.filePath = fileUri;
this.externalPath = externalPath;
}
/**
* Identifier for the song on the Android system.
* (so we can locate the file anywhere)
*/
public long getId() {
return id;
}
public Uri getFilePath() {
return filePath;
}
public Song setFilePath(Uri filePath) {
this.filePath = filePath;
return this;
}
private String title = "";
private String artist = "";
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public boolean isExternalPath() {
return externalPath;
}
public Song setIsExternalPath(boolean externalPath) {
this.externalPath = externalPath;
return this;
}
}
现在在您的 Util 类中,或者如果您希望创建一个静态方法,该类将查询媒体存储中的所有音频文件:
public static List getAllExternalAudioSongs(Context c) { List songList = new ArrayList<>(); ContentResolver contentResolver = c.getContentResolver();
List<Uri> contentUriLists = new ArrayList<>();
contentUriLists.add(MediaStore.Audio.Media.INTERNAL_CONTENT_URI);
contentUriLists.add(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
String selection= MediaStore.Audio.Media.DURATION + ">= 3000";
boolean externalPath = false;
for (Uri uri : contentUriLists) {
Cursor cursor = contentResolver.query(uri, null, selection, null, android.provider.MediaStore.Audio.Media.TITLE+ " ASC");
if (cursor == null) {
// query failed, handle error.
} else if (!cursor.moveToFirst()) {
// no media on the device
} else {
int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
do {
long id = cursor.getLong(idColumn);
String title = cursor.getString(titleColumn);
String artist = cursor.getString(artistColumn);
Uri contentUri = ContentUris.withAppendedId(
uri, id);
Song song = new Song(id, title, artist, contentUri, externalPath);
songList.add(song);
} while (cursor.moveToNext());
externalPath=true;
}
}
return songList;
}
注意:externalPath 只是为了区分内部音频文件和外部音频文件。
最后,在preferenceActivity(或片段)的onCreate中,您可以这样做:
private void setRingtoneList() {
ListPreference listPreferenceCategory = (ListPreference) findPreference("myRingtone");
if (listPreferenceCategory != null) {
List<Song> songList = Utils.getAllExternalAudioSongs(getApplicationContext());
CharSequence entries[] = new String[songList.size()];
CharSequence entryValues[] = new String[songList.size()];
int i = 0;
for (Song song : songList) {
entries[i] = song.getTitle();
entryValues[i] = song.getFilePath().toString();
i++;
}
listPreferenceCategory.setEntries(entries);
listPreferenceCategory.setEntryValues(entryValues);
}
}
注意:您需要外部存储的运行时权限。并且要更新摘要,您必须在我相信的偏好活动中执行此操作。无论如何,这很好地说明了如何播放示例音频而不是整个音频文件。