如何在PreferenceFragmentCompat中实现RingtonePreference?
How to implement RingtonePreference in PreferenceFragmentCompat?
我正在使用一个 AppCompactActivity
创建一个应用程序,所有其他视图都使用 Fragment。所以我想用PreferenceFragmentCompat
。但是当我创建它时出现以下错误。
android.view.InflateException: Binary XML file line #12: Error inflating class (not found)RingtonePreference
at android.support.v7.preference.PreferenceInflater.createItemFromTag(PreferenceInflater.java:300)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:358)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:360)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:167)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:117)
at android.support.v7.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:115)
at android.support.v7.preference.PreferenceFragmentCompat.addPreferencesFromResource(PreferenceFragmentCompat.java:366)
at com.example.main.PreferenceFragmentSettings.onCreate(PreferenceFragmentSettings.java:18)
at android.support.v4.app.Fragment.performCreate(Fragment.java:1939)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:517)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Caused by: java.lang.ClassNotFoundException:
Didn't find class "android.support.v7.preference.RingtonePreference"
on path: DexPathList[[zip file "/data/app/com.example.main-1/base.apk"],
nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at android.support.v7.preference.PreferenceInflater.createItem(PreferenceInflater.java:233)
at android.support.v7.preference.PreferenceInflater.onCreateItem(PreferenceInflater.java:280)
at android.support.v7.preference.PreferenceInflater.createItemFromTag(PreferenceInflater.java:289)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:358)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:360)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:167)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:117)
at android.support.v7.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:115)
at android.support.v7.preference.PreferenceFragmentCompat.addPreferencesFromResource(PreferenceFragmentCompat.java:366)
at com.example.main.PreferenceFragmentSettings.onCreate(PreferenceFragmentSettings.java:18)
at android.support.v4.app.Fragment.performCreate(Fragment.java:1939)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:517)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Suppressed: java.lang.ClassNotFoundException:
android.support.v7.preference.RingtonePreference
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 25 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the
boot class loader; no stack available
请告诉我有什么方法可以在 PreferenceFragmentCompat
中实现 RingtonePreference
吗?
今天的铃声首选项在支持库中不存在。您需要使用框架的版本或创建自己的版本。
我想很快就会出现
不是我的解决方案,但我 post 无论如何,因为它有效。
In you preferences XML resource, change RingtonePreference to
Preference. Then, in your implementation of PreferenceFragment, add:
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (preference.getKey().equals(KEY_RINGTONE_PREFERENCE)) {
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI);
String existingValue = getRingtonePreferenceValue(); // TODO
if (existingValue != null) {
if (existingValue.length() == 0) {
// Select "Silent"
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
} else {
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(existingValue));
}
} else {
// No ringtone has been selected, set to the default
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Settings.System.DEFAULT_NOTIFICATION_URI);
}
startActivityForResult(intent, REQUEST_CODE_ALERT_RINGTONE);
return true;
} else {
return super.onPreferenceTreeClick(preference);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_ALERT_RINGTONE && data != null) {
Uri ringtone = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (ringtone != null) {
setRingtonPreferenceValue(ringtone.toString()); // TODO
} else {
// "Silent" was selected
setRingtonPreferenceValue(""); // TODO
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
如果您需要 XAMARIN.Droid 版本:
public override void OnActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == REQUEST_CODE_ALERT_RINGTONE && data != null)
{
var ringtone = data.GetParcelableExtra(RingtoneManager.ExtraRingtonePickedUri);
if (ringtone != null)
{
SetRingtonePreferenceValue(ringtone.ToString());
}
else
{
// "Silent" was selected
SetRingtonePreferenceValue("");
}
}
else
{
base.OnActivityResult(requestCode, resultCode, data);
}
}
public override bool OnPreferenceTreeClick(Android.Support.V7.Preferences.Preference preference)
{
if (preference.Key == KEY_RINGTONE_PREFERENCE)
{
Intent intent = new Intent(RingtoneManager.ActionRingtonePicker);
intent.PutExtra(RingtoneManager.ExtraRingtoneType, (int)RingtoneType.Notification);
intent.PutExtra(RingtoneManager.ExtraRingtoneShowDefault, true);
intent.PutExtra(RingtoneManager.ExtraRingtoneShowSilent, true);
intent.PutExtra(RingtoneManager.ExtraRingtoneDefaultUri, Android.Provider.Settings.System.DefaultRingtoneUri);
string existingValue = GetRingtonePreferenceValue();
if (existingValue != null)
{
if (existingValue.Length == 0)
{
// Select "Silent"
intent.PutExtra(RingtoneManager.ExtraRingtoneExistingUri, (Android.Net.Uri)null);
}
else
{
intent.PutExtra(RingtoneManager.ExtraRingtoneExistingUri, Android.Net.Uri.Parse(existingValue));
}
}
else
{
// No ringtone has been selected, set to the default
intent.PutExtra(RingtoneManager.ExtraRingtoneExistingUri, Android.Provider.Settings.System.DefaultRingtoneUri);
}
StartActivityForResult(intent, REQUEST_CODE_ALERT_RINGTONE);
return true;
}
return base.OnPreferenceTreeClick(preference);
}
void SetRingtonePreferenceValue(string ringtone)
{
var editor = prefs.Edit();
editor.PutString(KEY_RINGTONE_PREFERENCE, ringtone);
editor.Commit();
}
string GetRingtonePreferenceValue()
{
return prefs.GetString(KEY_RINGTONE_PREFERENCE, "content://settings/system/notification_sound");
}
这是我使用 androidx.preference:preference-ktx:1.1.1
基于 的 Kotlin 实现。我将铃声用于闹钟 - 因此措辞不同,TYPE_ALARM
和 DEFAULT_ALARM_ALERT_URI
。
class AppSettingsFragment : PreferenceFragmentCompat() {
// ...
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (REQUEST_CODE_ALARM_TONE == requestCode && data != null) {
val alarmToneUri = data.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
onAlarmTonePicked(alarmToneUri)
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
private fun onAlarmTonePicked(alarmToneUri: Uri?) {
repository.updateAlarmToneUri(alarmToneUri)
}
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
return if (getString(R.string.preference_key_alarm_tone) == preference?.key) {
onAlarmTonePreferenceClick()
} else {
super.onPreferenceTreeClick(preference)
}
}
private fun onAlarmTonePreferenceClick(): Boolean {
val alarmToneUri = repository.readAlarmToneUri()
val extras = bundleOf(
RingtoneManager.EXTRA_RINGTONE_TYPE to RingtoneManager.TYPE_ALARM,
RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT to true,
RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT to true,
RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI to Settings.System.DEFAULT_ALARM_ALERT_URI,
RingtoneManager.EXTRA_RINGTONE_EXISTING_URI to alarmToneUri
)
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { putExtras(extras) }
startActivityForResult(intent, REQUEST_CODE_ALARM_TONE)
return true
}
}
我正在使用一个 AppCompactActivity
创建一个应用程序,所有其他视图都使用 Fragment。所以我想用PreferenceFragmentCompat
。但是当我创建它时出现以下错误。
android.view.InflateException: Binary XML file line #12: Error inflating class (not found)RingtonePreference
at android.support.v7.preference.PreferenceInflater.createItemFromTag(PreferenceInflater.java:300)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:358)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:360)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:167)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:117)
at android.support.v7.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:115)
at android.support.v7.preference.PreferenceFragmentCompat.addPreferencesFromResource(PreferenceFragmentCompat.java:366)
at com.example.main.PreferenceFragmentSettings.onCreate(PreferenceFragmentSettings.java:18)
at android.support.v4.app.Fragment.performCreate(Fragment.java:1939)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:517)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Caused by: java.lang.ClassNotFoundException:
Didn't find class "android.support.v7.preference.RingtonePreference"
on path: DexPathList[[zip file "/data/app/com.example.main-1/base.apk"],
nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at android.support.v7.preference.PreferenceInflater.createItem(PreferenceInflater.java:233)
at android.support.v7.preference.PreferenceInflater.onCreateItem(PreferenceInflater.java:280)
at android.support.v7.preference.PreferenceInflater.createItemFromTag(PreferenceInflater.java:289)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:358)
at android.support.v7.preference.PreferenceInflater.rInflate(PreferenceInflater.java:360)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:167)
at android.support.v7.preference.PreferenceInflater.inflate(PreferenceInflater.java:117)
at android.support.v7.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:115)
at android.support.v7.preference.PreferenceFragmentCompat.addPreferencesFromResource(PreferenceFragmentCompat.java:366)
at com.example.main.PreferenceFragmentSettings.onCreate(PreferenceFragmentSettings.java:18)
at android.support.v4.app.Fragment.performCreate(Fragment.java:1939)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:517)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Suppressed: java.lang.ClassNotFoundException:
android.support.v7.preference.RingtonePreference
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 25 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the
boot class loader; no stack available
请告诉我有什么方法可以在 PreferenceFragmentCompat
中实现 RingtonePreference
吗?
今天的铃声首选项在支持库中不存在。您需要使用框架的版本或创建自己的版本。
我想很快就会出现
不是我的解决方案,但我 post 无论如何,因为它有效。
In you preferences XML resource, change RingtonePreference to Preference. Then, in your implementation of PreferenceFragment, add:
@Override public boolean onPreferenceTreeClick(Preference preference) { if (preference.getKey().equals(KEY_RINGTONE_PREFERENCE)) { Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI); String existingValue = getRingtonePreferenceValue(); // TODO if (existingValue != null) { if (existingValue.length() == 0) { // Select "Silent" intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null); } else { intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(existingValue)); } } else { // No ringtone has been selected, set to the default intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Settings.System.DEFAULT_NOTIFICATION_URI); } startActivityForResult(intent, REQUEST_CODE_ALERT_RINGTONE); return true; } else { return super.onPreferenceTreeClick(preference); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_ALERT_RINGTONE && data != null) { Uri ringtone = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); if (ringtone != null) { setRingtonPreferenceValue(ringtone.toString()); // TODO } else { // "Silent" was selected setRingtonPreferenceValue(""); // TODO } } else { super.onActivityResult(requestCode, resultCode, data); } }
如果您需要 XAMARIN.Droid 版本:
public override void OnActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == REQUEST_CODE_ALERT_RINGTONE && data != null)
{
var ringtone = data.GetParcelableExtra(RingtoneManager.ExtraRingtonePickedUri);
if (ringtone != null)
{
SetRingtonePreferenceValue(ringtone.ToString());
}
else
{
// "Silent" was selected
SetRingtonePreferenceValue("");
}
}
else
{
base.OnActivityResult(requestCode, resultCode, data);
}
}
public override bool OnPreferenceTreeClick(Android.Support.V7.Preferences.Preference preference)
{
if (preference.Key == KEY_RINGTONE_PREFERENCE)
{
Intent intent = new Intent(RingtoneManager.ActionRingtonePicker);
intent.PutExtra(RingtoneManager.ExtraRingtoneType, (int)RingtoneType.Notification);
intent.PutExtra(RingtoneManager.ExtraRingtoneShowDefault, true);
intent.PutExtra(RingtoneManager.ExtraRingtoneShowSilent, true);
intent.PutExtra(RingtoneManager.ExtraRingtoneDefaultUri, Android.Provider.Settings.System.DefaultRingtoneUri);
string existingValue = GetRingtonePreferenceValue();
if (existingValue != null)
{
if (existingValue.Length == 0)
{
// Select "Silent"
intent.PutExtra(RingtoneManager.ExtraRingtoneExistingUri, (Android.Net.Uri)null);
}
else
{
intent.PutExtra(RingtoneManager.ExtraRingtoneExistingUri, Android.Net.Uri.Parse(existingValue));
}
}
else
{
// No ringtone has been selected, set to the default
intent.PutExtra(RingtoneManager.ExtraRingtoneExistingUri, Android.Provider.Settings.System.DefaultRingtoneUri);
}
StartActivityForResult(intent, REQUEST_CODE_ALERT_RINGTONE);
return true;
}
return base.OnPreferenceTreeClick(preference);
}
void SetRingtonePreferenceValue(string ringtone)
{
var editor = prefs.Edit();
editor.PutString(KEY_RINGTONE_PREFERENCE, ringtone);
editor.Commit();
}
string GetRingtonePreferenceValue()
{
return prefs.GetString(KEY_RINGTONE_PREFERENCE, "content://settings/system/notification_sound");
}
这是我使用 androidx.preference:preference-ktx:1.1.1
基于 TYPE_ALARM
和 DEFAULT_ALARM_ALERT_URI
。
class AppSettingsFragment : PreferenceFragmentCompat() {
// ...
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (REQUEST_CODE_ALARM_TONE == requestCode && data != null) {
val alarmToneUri = data.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
onAlarmTonePicked(alarmToneUri)
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
private fun onAlarmTonePicked(alarmToneUri: Uri?) {
repository.updateAlarmToneUri(alarmToneUri)
}
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
return if (getString(R.string.preference_key_alarm_tone) == preference?.key) {
onAlarmTonePreferenceClick()
} else {
super.onPreferenceTreeClick(preference)
}
}
private fun onAlarmTonePreferenceClick(): Boolean {
val alarmToneUri = repository.readAlarmToneUri()
val extras = bundleOf(
RingtoneManager.EXTRA_RINGTONE_TYPE to RingtoneManager.TYPE_ALARM,
RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT to true,
RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT to true,
RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI to Settings.System.DEFAULT_ALARM_ALERT_URI,
RingtoneManager.EXTRA_RINGTONE_EXISTING_URI to alarmToneUri
)
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { putExtras(extras) }
startActivityForResult(intent, REQUEST_CODE_ALARM_TONE)
return true
}
}