アプリケーションのすべてのプロファイルのリストを保持するフラグメントがあります。このリストはカスタム BaseAdapter を使用します。このアダプタの仕様は次のとおりです。
- ユーザーは一度に 1 つのプロファイルのみを有効にできます。
- ユーザーがすべてのプロファイルを無効にしようとすると、警告が表示され、最後に有効にしたプロファイルが有効に戻されます。
- ユーザーが構成されていないプロファイルを有効にしようとすると、警告が表示され、最後に有効にされたプロファイルが有効に戻されます。
- ユーザーは各プロファイルを構成できます。
リストが最初に作成されたときに存在する現在の実装には、次の 1 つの問題があります。
- リストが最初に作成されたときにユーザーがリスト内の最初のプロファイルを有効にした場合 (ユーザーが [切り替え] をオンにした場合)、別のプロファイルを有効にしようとすると、最初のプロファイルが選択されたままになります ([切り替え] がオンになったままになります)。また、最初のプロファイルがチェックされた場合でも、実際に有効なプロファイルは後でチェックされるプロファイルになることに注意してください。
- 他のプロファイルが選択されている場合、これは発生しません。他のプロファイルが有効になると、他のすべてのプロファイルが無効になります。
- ただし、アクティビティを一時停止して再開すると、すべてが期待どおりに機能します。つまり、最初のスイッチがまだチェックされているという問題はなくなります。
以下は、この問題のグラフィック表示です。
BaseAdapter (AdapterProfiles) をホストするこのフラグメントのコードを次に示します。PreferenceData は、共有設定に関連するすべてを処理するクラスです。
public class Profiles extends Fragment implements OnCustomClickListener {
private View view_profiles;
private ListView lv_profiles;
private PreferenceData dataPreferenceObj;
private AdapterProfiles adapter;
private ArrayList<String> profileList = new ArrayList<String>();
private final ArrayList<HashMap<String, String>> profilesList = new ArrayList<HashMap<String, String>>();
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// ...
lv_profiles = (ListView) view_profiles.findViewById(R.id.lv_profiles);
// ...
}
@Override
public void onResume() {
createProfileList();
// Registers broadcast receiver
super.onResume();
}
private void createProfileList() {
if (profilesList.isEmpty() == true) {
profileList = new ProfileList().getProfileList();
for (int i = 0; i < profileList.size(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(Keys.KEY_PROFILE.toString(), profileList.get(i));
profilesList.add(map);
}
}
adapter = new AdapterProfiles(getActivity(), profilesList, this);
lv_profiles.setAdapter(adapter);
}
/*
* This is a custom onclick listener that gets handle from of list from
* LazyAdapterProfiles
*/
@Override
public void OnCustomClick(View view, int position) {
switch (view.getId()) {
case R.id.iv_profiles_settings:
// Opens setting for settings of profile clicked on
break;
case R.id.sw_profiles:
Switch sw_profiles = (Switch) view.findViewById(R.id.sw_profiles);
// Stops user from enabling profile that is not configured.
if (dataPreferenceObj.getTemporaryRingtoneUri().equals("") == true
|| dataPreferenceObj.getTemporaryLocation().equals("") == true) {
sw_profiles.setChecked(false);
showWarningDialog(
"Profile Disabled",
"Profile location and ringtone must be selected in order to enable this profile.");
} else if (dataPreferenceObj.getTemporaryRingtoneUri().equals("") != true
&& dataPreferenceObj.getTemporaryLocation().equals("") != true) {
if (sw_profiles.isChecked() == true) {
unselectProfileState(position);
} else if (sw_profiles.isChecked() == false) {
// Stops user from disabling profile as atleast one profile
// must be enabled
showWarningDialog("Profile Cannot Disable",
"Atleast one profile must be enabled");
sw_profiles.setChecked(true);
}
// Rest of the code that writes the preference and broadcast it
}
break;
}
}
// Gets switch map of all profiles and uncheck profile other than one that
// is selected.
private void unselectProfileState(int position) {
for (int i = 0; i < profileList.size(); i++) {
if (position != i) {
AdapterProfiles.getMapHolder().get(i).sw_profiles
.setChecked(false);
}
}
}
}
カスタム BaseAdapter があり、その各行には、次のような TextView、ImageView、および Switch が保持されます。
リストに行を作成する BaseAdapter の実装は次のとおりです。
public class AdapterProfiles extends BaseAdapter {
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater = null;
private String profile_name;
private String retrived_profile_name;
private ViewHolder holder;
private Activity activity;
private OnCustomClickListener callback;
private static SparseArray<ViewHolder> mapHolder = new SparseArray<ViewHolder>();
public AdapterProfiles(Activity activity,
ArrayList<HashMap<String, String>> data,
OnCustomClickListener callback) {
this.activity = activity;
this.data = data;
this.callback = callback;
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public AdapterProfiles(Activity activity,
ArrayList<HashMap<String, String>> data) {
this.data = data;
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.ui_profiles_row, null);
holder = new ViewHolder();
holder.tv_profiles_name = (TextView) convertView
.findViewById(R.id.tv_profiles_name);
holder.tv_profiles_location_name = (TextView) convertView
.findViewById(R.id.tv_profiles_location_name);
holder.iv_profiles_settings = (ImageView) convertView
.findViewById(R.id.iv_profiles_settings);
holder.sw_profiles = (Switch) convertView
.findViewById(R.id.sw_profiles);
holder.iv_profiles_settings
.setOnClickListener(new CustomOnClickListener(callback,
position));
holder.sw_profiles.setOnClickListener(new CustomOnClickListener(
callback, position));
convertView.setTag(holder);
mapHolder.put(position, holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
getPrefs(position);
setUIData();
return convertView;
}
private void getPrefs(int position) {
HashMap<String, String> word = new HashMap<String, String>();
word = data.get(position);
profile_name = word.get(Keys.KEY_PROFILE.toString());
SharedPreferences settings = activity.getSharedPreferences(
Keys.PREFS_APP.toString(), 0);
// This allows us to retrive unique data based on the profile names
String PROFILE_LOCATION = Keys.KEY_LOCATION.toString() + "_"
+ profile_name;
retrived_profile_name = settings.getString(Keys.KEY_PROFILE.toString(),
"");
}
// Sets UI data of item in the list
private void setUIData() {
if (profile_name.equals(retrived_profile_name) == true) {
holder.sw_profiles.setChecked(true);
} else if (profile_name.equals(retrived_profile_name) == false) {
holder.sw_profiles.setChecked(false);
}
}
public static class ViewHolder {
public ImageView iv_profiles_settings;
public TextView tv_profiles_location_name;
public TextView tv_profiles_name;
public Switch sw_profiles;
}
public static SparseArray<ViewHolder> getMapHolder() {
return mapHolder;
}
}
最後に、誰かが疑問に思っている場合は、CustomOnClickListener クラスを示します。このクラスの実装は、コールバックをリスト内の特定のコンポーネントにマップすることです。このクラスはもともと誰かによって作成されたもので (私のブックマークには作成者の名前がありませんでした)、私は彼/彼女のサンプルを使用して自分の実装に適合させました。そのためのコードは次のとおりです。
public class CustomOnClickListener implements OnClickListener {
private int position;
private OnCustomClickListener callback;
public CustomOnClickListener(OnCustomClickListener callback, int position) {
this.position = position;
this.callback = callback;
}
@Override
public void onClick(View v) {
callback.OnCustomClick(v, position);
}
}
public interface OnCustomClickListener {
public void OnCustomClick(View view, int position);
}