在首选项中,像使用RingtonePreference一样select我的声音

我的声音在我的/ raw文件夹中,我希望我的用户能够在首选项中select一个完全像RingtonePreference一样的声音,但只能用我的声音。

Solutions Collecting From Web of "在首选项中,像使用RingtonePreference一样select我的声音"

在这里我的RingtonePreferencereplace。 列出所有系统铃声和自定义铃声(在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); } } } 

RES /值/ 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 /值/ 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 /生

 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中创build自己的样式:

 <?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中,我修改了onPrepareDialogBu​​ilder方法来播放我点击的项目上的声音。

  @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; } } 

希望这将有助于某人。

当进行铃声首选项定制时,我更喜欢铃声只播放短时间,有点像样品的声音。 如果用户只是从列表中select声音,用户不需要听到整个声音播放。 这是我如何实现这一点:

首先创build一个将播放铃声的服务(使用铃声pipe理器来播放声音,而不是媒体播放器,因为它处理我们的取消):

公共类PlayRingtoneService扩展Service {静态铃声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" /> 

然后使用上面的解决scheme,但修改您可以创build一个列表首选项,行为就像一个铃声首选项:

 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" /> 

现在要真正加载到列表中的值,我们创build一个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类或者只是一个静态的方法,如果你想让你做这个类将查询所有audio文件的媒体存储:

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只是如果你想区分内部和外部的audio文件。

最后,在preferenceActivity(或fragment)的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); } } 

注意:您将需要外部存储的运行时权限。 也更新总结,你必须在偏好活动中做到这一点,我相信。 无论如何,这给了一个好主意,如何播放示例audio,而不是整个audio文件。