2012-08-03 51 views

回答

3

因此,最后我查看了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我修改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); 
} 
+1

嗨。 您可以发送或邮寄的全部源代码。 问候, 托尼 – toni 2012-11-09 09:20:00

+0

请发表您的自定义列表偏好的全部代码。 – 2013-02-27 11:46:03

2

下面是一个自定义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; 
} 
} 

希望这会有所帮助的人。

+1

感谢这篇文章!奇妙地工作!救了我的时间:) – 2013-04-04 09:16:44

14

在这里我的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); 
     } 


    } 


} 

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

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>  
+0

作品几乎开箱,只是有点修复:删除uriFromRaw(context参数),并使用mContext 此外,作为一个功能要求,这将是很好的显示选择的铃声的名字偏好的二号线(介绍),这样用户就可以看到选择的铃声,而不需要输入完成弹出 – Gavriel 2015-06-24 07:17:28

+0

!从uriFromRaw()中删除了上下文参数,add getSummary():-) – almisoft 2015-06-24 12:08:18

+0

谢谢!它很快!它可以在手动将铃声手动更改为我选择的任何内容后生效。之后,即使只显示首选项屏幕,也会显示摘要。但是在我第一次设置铃声时,摘要是空的。我想,没关系,但可以在xml中添加默认值(或者以某种方式)?例如auto:defaultValue =“@ + id/madonna_like_a_virgin”,auto:defaultValue =“”(用于系统默认铃声)或auto:defaultValue =“null”(用于静音) – Gavriel 2015-06-24 14:04:18

0

,有点像样品的声音。如果用户只是从列表中选择声音,用户不需要听到整个声音播放。这是我如何做到这一点:

首先创建一个服务,将播放铃声(以及使用的铃声管理器来播放声音,而不是媒体播放器作为其处理为我们取消):

公共类PlayRingtoneService扩展服务{ static铃声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类或只是如果你想这样做使这个类,将查询介质存储用于所有音频文件的静态方法:

公共静态列表getAllExternalAudioSongs(上下文C){ 列表的SongList =新的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); 
    } 
} 

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

相关问题