之前发过一篇有关于自定义preference 在ActivityGroup 的包容下出现UI不能更新的问题,当时还以为是Android 的一个BUG 现在想想真可笑 。其实是自己对机制的理解不够深刻,看来以后要多看看源码才行。
本篇讲述内容大致为如何自定义preference 开始到与ActivityGroup 互用下UI更新的解决方法。
首先从扩展preference开始:
类文件必须继承自Preference并实现构造函数,这里我一般实现两个构造函数分别如下(类名为:test):
publictest(Contextcontext){
this(context,null);
//TODOAuto-generatedconstructorstub
}
publictest(Contextcontext,AttributeSetattrs){
super(context,attrs);
//TODOAuto-generatedconstructorstub
}
这里第二个构造函数第二个参数为可以使用attrs 为我们自定义的preference 添加扩展的注册属性,比如我们如果希望为扩展的preference 添加一个数组引用,就可使用如下代码:
intresouceId=attrs.getAttributeResourceValue(null,"Entries",0);
if(resouceId>0){
mEntries=getContext().getResources().getTextArray(resouceId);
}
这里的mEntries 是头部声明的一个数组,我们可以在xml文件通过 Entries=数组索引得到一个数组。在这里不深入为大家示范了。
我们扩展preference 有时想让其UI更丰富更好看,这里我们可以通过引用一个layout 文件为其指定UI,可以通过实现如下两个回调函数:
@Override
protectedViewonCreateView(ViewGroupparent){
//TODOAuto-generatedmethodstub
returnLayoutInflater.from(getContext()).inflate(
R.layout.preference_screen,parent,false);
}
此回调函数与onBindView 一一对应,并优先执行于onBindView ,当创建完后将得到的VIEW返回出去给onBindView处理,如下代码:
@Override
protectedvoidonBindView(Viewview){
//TODOAuto-generatedmethodstub
super.onBindView(view);
canlendar=Calendar.getInstance();
layout=(RelativeLayout)view.findViewById(R.id.area);
title=(TextView)view.findViewById(R.id.title);
summary=(TextView)view.findViewById(R.id.summary);
layout.setOnClickListener(this);
title.setText(getTitle());
summary.setText(getPersistedString(canlendar.get(Calendar.YEAR)+"/"
+(canlendar.get(Calendar.MONTH)+1)+"/"
+canlendar.get(Calendar.DAY_OF_MONTH)));
}
Tip:onBindView 不是必须的,可以将onBindView 里的处理代码在onCreateView 回调函数一并完成然后返回给onBindView ,具体怎么写看自己的代码风格吧。我个人比较喜欢这种写法,比较明了。
下面我们来了解一下我扩展preference 比较常用到的几个方法:
-
compareTo(Preferenceanother)
与另外一个preference比较,如果相等则返回0,不相等则返回小于0的数字。
-
getContext()
获取上下文
-
getEditor()
得到一个SharePrefence 的Editor 对象
-
getIntent()
获取Intetn
-
getKey()
获取当前我们在XML为其注册的KEY
-
getLayoutResource()
得到当前layout 的来源
-
getOnPreferenceChangeListener()
值改变的监听事件
-
getPreferenceManager()
获得一个preference管理
-
getSharedPreferences()
通过获得管理获取当前的sharePreferences
-
getSummary()
获得当前我们在XML为其注册的备注为summary 的值。Tip:在OnBindView 或者onCreateView 找到VIEW的时候如果存在summary 的View 对象必须为其设置summary
-
getTitle()
如上,不过这里是获取标题
-
callChangeListener(ObjectnewValue)
如果你希望你扩展的Preference 可以支持当数值改变时候可以调用OnPreferenceChangeListener此监听方法,则必须调用此方法,查看该方法源码为:
protectedbooleancallChangeListener(ObjectnewValue){
returnmOnChangeListener==null?true:mOnChangeListener.onPreferenceChange(this,newValue);
}
源码简单不做过多介绍,只是实现一个接口。
-
getPersistedBoolean(boolean
defaultReturnValue)
获得一个保存后的布尔值,查看一下源码:
protectedbooleangetPersistedBoolean(booleandefaultReturnValue){
if(!shouldPersist()){
returndefaultReturnValue;
}
returnmPreferenceManager.getSharedPreferences().getBoolean(mKey,defaultReturnValue);
}
如果你有接触过sharePreference 相信一眼就能看出这里它为我们做了什么。
-
getPersistedFloat(float
defaultReturnValue)
如上,这里获取一个Float 的值
-
getPersistedInt(int
defaultReturnValue)
如上,获取一个int 的值
-
getPersistedLong(long
defaultReturnValue)
如上,获取一个Long 型数值
-
getPersistedString(StringdefaultReturnValue)
如上,获取一个String 数值
-
persistBoolean(boolean
value)
将一个布尔值保存在sharepreference中,查看一下源码:
protectedbooleanpersistBoolean(booleanvalue){
if(shouldPersist()){
if(value==getPersistedBoolean(!value)){
//It'salreadythere,sothesameaspersisting
returntrue;
}
SharedPreferences.Editoreditor=mPreferenceManager.getEditor();
editor.putBoolean(mKey,value);
tryCommit(editor);
returntrue;
}
returnfalse;
}
都是sharePreference 的知识,这里不做过多介绍。其他的跟上面的都 一样,略过。
通过如上的一些设置,一个基本的扩展preference 就己经完成,下面来讲讲如果在ActivityGroup 里面让扩展的preference可以更新UI。之前 农民伯伯 探讨过,他建议我使用onContentChanged()方法,可以使UI更新 ,试了一下发现有些许问题,不过非常感谢农民伯伯。这个方法是全局刷新,则全部UI都刷新一次,但是这样不是很合理,我想了一下,那既然此方法可以更新UI那么一定可以行得通,我查看一下源码,下面把源码贴出来:
@Override
publicvoidonContentChanged(){
super.onContentChanged();
postBindPreferences();
}
/**
*Postsamessagetobindthepreferencestothelistview.
*<p>
*Bindinglateispreferredasanycustompreferencetypescreatedin
*{@link#onCreate(Bundle)}areabletohavetheirviewsrecycled.
*/
privatevoidpostBindPreferences(){
if(mHandler.hasMessages(MSG_BIND_PREFERENCES))return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
privatevoidbindPreferences(){
finalPreferenceScreenpreferenceScreen=getPreferenceScreen();
if(preferenceScreen!=null){
preferenceScreen.bind(getListView());
}
}
privatestaticfinalintMSG_BIND_PREFERENCES=0;
privateHandlermHandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
switch(msg.what){
caseMSG_BIND_PREFERENCES:
bindPreferences();
break;
}
}
};
原来,这里它是另开一条线程来更新UI,然后当值发生变化时为其发送消息,在消息队列里面处理UI,只不过它这里继承了listActivity 更新了一整个listView ,那么我们就将它提取出来,只更新我们想要的UI则可。OK,思路出来了,下面将我扩展的一个preference 的源码提供出来:
packagecom.yaomei.preference;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importandroid.app.Dialog;
importandroid.content.Context;
importandroid.content.DialogInterface;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.preference.Preference;
importandroid.preference.PreferenceGroup;
importandroid.util.AttributeSet;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.view.View.OnClickListener;
importandroid.widget.AdapterView;
importandroid.widget.ListView;
importandroid.widget.RelativeLayout;
importandroid.widget.SimpleAdapter;
importandroid.widget.TextView;
importandroid.widget.AdapterView.OnItemClickListener;
importcom.yaomei.set.R;
publicclassPreferenceScreenExtextendsPreferenceGroupimplements
OnItemClickListener,DialogInterface.OnDismissListener{
privateDialogdialog;
privateTextViewtitle,summary;
privateRelativeLayoutarea;
privateListViewlistView;
List<Preference>list;
privateList<HashMap<String,String>>listStr;
privateCharSequence[]mEntries;
privateStringmValue;
privateSimpleAdaptersimple;
privatestaticfinalintMSG_BIND_PREFERENCES=0;
privateHandlermHandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
switch(msg.what){
caseMSG_BIND_PREFERENCES:
setValue(mValue);
break;
}
}
};
publicPreferenceScreenExt(Contextcontext,AttributeSetattrs){
this(context,attrs,android.R.attr.preferenceScreenStyle);
//TODOAuto-generatedconstructorstub
}
publicPreferenceScreenExt(Contextcontext,AttributeSetattrs,intdefStyle){
super(context,attrs,android.R.attr.preferenceScreenStyle);
//TODOAuto-generatedconstructorstub
intresouceId=attrs.getAttributeResourceValue(null,"Entries",0);
if(resouceId>0){
mEntries=getContext().getResources().getTextArray(resouceId);
}
}
@Override
protectedvoidonBindView(Viewview){
//TODOAuto-generatedmethodstub
area=(RelativeLayout)view.findViewById(R.id.area);
title=(TextView)view.findViewById(R.id.title);
summary=(TextView)view.findViewById(R.id.summary);
title.setText(getTitle());
summary.setText(getPersistedString(getSummary().toString()));
area.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
//TODOAuto-generatedmethodstub
showDialog();
}
});
}
@Override
protectedViewonCreateView(ViewGroupparent){
//TODOAuto-generatedmethodstu
Viewview=LayoutInflater.from(getContext()).inflate(
R.layout.preference_screen,parent,false);
returnview;
}
publicvoidbindView(ListViewlistview){
intlength=mEntries.length;
inti=0;
listStr=newArrayList<HashMap<String,String>>();
for(i=0;i<length;i++){
HashMap<String,String>map=newHashMap<String,String>();
map.put("keyname",mEntries[i].toString());
listStr.add(map);
}
simple=newSimpleAdapter(getContext(),listStr,R.layout.dialog_view,
newString[]{"keyname"},newint[]{R.id.text});
listview.setAdapter(simple);
listview.setOnItemClickListener(this);
}
publicvoidshowDialog(){
listView=newListView(getContext());
bindView(listView);
dialog=newDialog(getContext(),android.R.style.Theme_NoTitleBar);
dialog.setContentView(listView);
dialog.setOnDismissListener(this);
dialog.show();
}
@Override
publicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,
longid){
//TODOAuto-generatedmethodstub
mValue=listStr.get(position).get("keyname").toString();
persistString(mValue);
callChangeListener(mValue);
dialog.dismiss();
}
@Override
publicvoidonDismiss(DialogInterfacedialog){
//TODOAuto-generatedmethodstub
}
privateOnPreferenceChangeListenertemp;
publicinterfaceOnPreferenceChangeListener{
publicbooleanonPreferenceChange(Preferencepreference,ObjectnewValue);
}
publicvoidsetOnPreferenceChangeListener(
OnPreferenceChangeListenerpreference){
this.temp=preference;
}
publicvoidsetValue(Stringvalue){
summary.setText(value);
}
publicbooleancallChangeListener(ObjectnewValue){
returntemp==null?true:temp.onPreferenceChange(this,newValue);
}
publicvoidpostBindPreferences(){
if(mHandler.hasMessages(MSG_BIND_PREFERENCES))
return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
}
然后在preferenceActivity 界面在回调函数:onPreferenceChange调用postBindPreferences即可更新。
Tip:这里的onPreferenceChange调用postBindPreferences 不是必须的,你同样可以在内部里面实现,通过执行某一操作发送消息也可。
好了,在这里我要感谢那几位朋友对我的帮助,提出了很多宝贵的意见。谢谢。
分享到:
相关推荐
上篇博文代码实现了Android自带的preference组件,本文将通过实例讲解自定义preference组件。 主要通过以下几步来实现: 1.定义需要的layout布局res->layout->xml文件; 2.通过继承Preference类,来实现自定义...
android Preference自定义样式
Android 自定义PreferenceActivity
自定义preference的checkboxpreference样式
本文举例说明在Preference中自定义layout的方法。笔者是为了在设置中插入@有米v4广告条才研究了一晚上的。正文:首先PreferenceScreen是一个xml文件于res/xml目录下,不属于layout文件。要插入layout,有两种方法。 ...
Based on support-preference from Android Support Library, adding a lot of exciting features. Sample How to use add dependencies // replace with version above implementation 'moe.shizuku.preference...
假如你需要RadioPreference或者一个带特殊功能的Preferece,当然你会选择了自定义一个Preference控件,但是会发现,自定义的Preference中Switch,CheckBox,Radio的动画效果没掉了,实在捉急。其实是因为android在...
假如你需要RadioPreference或者一个带特殊功能的Preferece,你可以选择了自定义一个Preference控件,不过你会发现,自定义的Preference中Switch,CheckBox,Radio的动画效果没掉了。其实是因为android在Preferece里面...
Preference组件是android的SharePreferences的衍生品,Preference组件的状态值是默认永久的保存在/data/data/包名/shared_prefs ...Preference组件其实就是Android常见UI组件与SharePreferences的组合封装实现。
Android应用源码之Preference_Demo.zip项目安卓应用源码下载Android应用源码之Preference_Demo.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
很想做个天气预警的功能, 想用preferences来做界面。 看了很多preferences感觉定制性太差 所以自己做了一个。 应该是不错的demo 定制preferences在preferencesActivity中的布局 和自定义了对话框的布局
android-support-v7-preference.jar
Android-Support-Preference-V7-Fix-master.zip Android-Support-Preference-V7-Fix-master.zip
Android中Preference的使用以及监听事件分析
安卓Android源码——Preference_Demo.rar
这是Pro Android学习系列中preference部分的例子源代码。
Android中preference的使用,使用详解.
扩展的AndroidX首选项该库旨在解决在官方AndroidX首选项库中发现的一些问题。 另外,还有可用,例如RingtonePreference , DatePickerPreference和TimePickerPreference 。捐款如果您想支持我,您可以通过PayPal捐款...
Android提供preference这个键值对的方式来处理这种情况,自动保存这些数据,并立时生效,同时Android提供一种类似的layout的方式来进行Preference的布局。 Preference组件有ListPreference,EditTextPreference,...
Android应用源码开发Demo,主要用于毕业设计学习。