- 我们知道系统Preference提供的控件并不多,只有CheckBoxPreference,ListPreference,EditTextPreference,RingtonePreference等为数不多的控件,有时候并不能满足我们的需求.这时候我们就需要自定义,比如自定义一个SeekBar用来调节音量什么的.这里我就不介绍如何自定义包含SeekBar的Preference,大家可以查看Android自定义SeekBarPreference.
这里需要提及的是,我们自定的这个控件,往往需要和Activity或者Service通信,这时候该怎么操作呢?
我们同样还是以SeekBarPreference为例.我们都知道,当滑动SeekBar的时候,系统会回调onProgressChanged方法.假如我们需要在onProgressChanged中与
Activity/Fragment/Service通信.这时候就需要定义一个接口在其中声明我们需要用到的方法.然后声明一个函数,将接口的引用作为参数提供给Activity/Fragment/
Service调用.
public class VolumeSeekBarPreferences extends DialogPreference implements OnSeekBarChangeListener {
private seekBarCallBack back;
....
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
....
back.setSeekBarVolume(mCurrentValue);
....
}
....
public interface seekBarCallBack{
public void setSeekBarVolume(int volume);
}
public void setSeekbarListener(seekBarCallBack barCallBack){
back = barCallBack;
}
}
然后,在Activity/Fragment/Service中通过实现控件Preference中的传递接口引用的函数.
public class MyPreferenceFragment extends PreferenceFragment implements
OnPreferenceClickListener, OnPreferenceChangeListener {
private VolumeSeekBarPreferences seekBarPreferences;
.....
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.preference_setting);
//VolumeSeekBarPreferences为我们自定义的Preference控件
seekBarPreferences = (VolumeSeekBarPreferences) findPreference("seekBarPreference");
seekBarPreferences.setSeekbarListener(new seekBarCallBack() {
@Override
public void setSeekBarVolume(int volume) {
// TODO Auto-generated method stub
//在这里实现通信
}
});
}
.....
}
2.Fragment如何调用Service的方法?
Fragment和Activity的通信大家都知道,可以通过在Fragment声明接口,然后在Activity中implements这个接口
public class MyPreferenceFragment extends PreferenceFragment implements
OnPreferenceClickListener, OnPreferenceChangeListener{
private Activity context;
.....
@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
context = activity;
try {
callbackSetting = (CallbackSetting) context;
} catch (Exception e) {
// TODO: handle exception
}
}
.....
/*
* 利用回调函数,让IntentActivity调用Service的方法来实现Fragment间接调用Service的方法
*/
public interface CallbackSetting {
public int getVolume();
public void setVolume(int volume);
public void setRemoteModel(boolean flag);
public void readModelInfo();
}
......
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// TODO Auto-generated method stub
if(preference == checkBoxRemote){
if((Boolean)newValue){
callbackSetting.setRemoteModel(true);
}else {
callbackSetting.setRemoteModel(false);
}
}
return true;
}
......
}
Activity中:
public class IntentActivity extends Activity implements ServiceConnection, CallbackSetting{
......
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.empty_layout);
Intent settingIntent = new Intent("com.example.RadioService");
this.bindService(settingIntent, this, BIND_AUTO_CREATE);
}
.......
@Override
public void setRemoteModel(boolean flag) {
// TODO Auto-generated method stub
if(flag){
radioService.setRemote(1);
}else {
radioService.setRemote(0);
}
}
......
}
因为Activity可以通过bindService绑定Service并调用Service中的方法.所以这里,Activity只是通过实现Fragment的接口来充当中介.
3.Fragment中是可以发送和接收Broadcast的
......
@Override
public void onAttach(Activity activity) {
/** 注册广播 */
receiveBroadCast = new ReceiveBroadCast();
IntentFilter filter = new IntentFilter();
filter.addAction("com.gasFragment"); //只有持有相同的action的接受者才能接收此广播
activity.registerReceiver(receiveBroadCast, filter);
super.onAttach(activity);
}
......
class ReceiveBroadCast extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
//得到广播中得到的数据,并显示出来
String gasname = intent.getExtras().getString("gasName");
String address = intent.getExtras().getString("address");
gasadderss.setText("地址:\n "+address);
gasName.setText(gasname);
}
}
/**
*注销广播
* */
@Override
public void onDestroyView() {
getActivity().unregisterReceiver(receiveBroadCast);
super.onDestroyView();
}
......
4.如何在其他的Activity/Service中获取Preference保存的值
在Activity/Service调用以下代码就可以获取Preference保存的值,很简单~
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mRemote = prefs.getBoolean("checkbox_remote_preference", true);//两个参数,一个是Preference控件的android:key属性,
//另一个是取不到值时的默认值
当一个Preference控件实现这两个接口时,当被点击或者值发生改变时,触发方法是如何执行的呢?事实上,
它的触发规则如下:
1 先调用onPreferenceClick()方法,如果该方法返回true,则不再调用onPreferenceTreeClick方法 ;
如果onPreferenceClick方法返回false,则继续调用onPreferenceTreeClick方法。
2 onPreferenceChange的方法独立与其他两种方法的运行。也就是说,它总是会运行。
补充:1 点击某个Preference控件后,会先回调onPreferenceChange()方法,即是否保存值,然后再回调onPreferenceClick以及onPreferenceTreeClick()方法,
因此在onPreferenceClick/onPreferenceTreeClick方法中我们得到的控件值就是最新的Preference控件值。
2 如果是自定义的Preference控件,且点击Preference列表后出现新窗口那么该控件会直接调用onPreferenceTreeClick方法,而不调用onPreferenceClick,
因为onPreferenceClick中没有PreferenceScreen参数
它的触发规则如下:
1 先调用onPreferenceClick()方法,如果该方法返回true,则不再调用onPreferenceTreeClick方法 ;
如果onPreferenceClick方法返回false,则继续调用onPreferenceTreeClick方法。
2 onPreferenceChange的方法独立与其他两种方法的运行。也就是说,它总是会运行。
补充:1 点击某个Preference控件后,会先回调onPreferenceChange()方法,即是否保存值,然后再回调onPreferenceClick以及onPreferenceTreeClick()方法,
因此在onPreferenceClick/onPreferenceTreeClick方法中我们得到的控件值就是最新的Preference控件值。
2 如果是自定义的Preference控件,且点击Preference列表后出现新窗口那么该控件会直接调用onPreferenceTreeClick方法,而不调用onPreferenceClick,
因为onPreferenceClick中没有PreferenceScreen参数