Realm 不断调用 onChange addChangeListener
Realm calling onChange addChangeListener continuously
如果解释得不好,我深表歉意,我自己也很难理解。如果您指出任何您不理解的地方,我会尽力纠正任何问题。好的,我们开始吧。
几个类。 (D&D sheet, sheet 有用户可以装备的武器,这是关于装备存储在列表中的所述武器)
- 片段activity - CombatFragment
- 在CombatFragment中声明的arrayadapter列表 -
AttackListViewContentAdapter
- 领域对象 - Weapon
- 持有武器列表的领域对象 - Sheet
- 一些XML个文件(我不会在这里粘贴的代码因为SO有代码限制。content_combat, attack_list_item
到目前为止我收集到的是,当我创建一个新的 attackListViewContentAdapter 时,它会以快速且持续的速度循环。如此之多,以至于屏幕对我触摸任何小部件都没有反应。我做了一些事情,比如每次通过时记录一个数字,这样它就会一次又一次地显示出来。如果您需要这方面的信息,我可以告诉您我将日志放在哪里以及在我添加其他视图(行)时 Logcat 中显示的内容。
我相信这与一直被触发的 onChangedListener 有关变化。
为了 space 的利益,请注意我将使用缩写代码。我忽略了不相关的对话框和小部件之类的东西。因此,如果它似乎缺少某些东西或者您需要查看 类,它可能在我在每个文件上方链接的文件中。
public class CombatFragment extends Fragment {
@BindView(R.id.lv_attack_spellcasting_content)
ListView lv_attack_spellcasting_title;
@Nullable
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.content_combat, container, false);
RealmList<Weapon> weaponList = sheet.getWeaponList();
final AttackListViewContentAdapter attackListViewContentAdapter = new AttackListViewContentAdapter(getActivity(), sheet, realm, weaponList);
weaponList.addChangeListener(new RealmChangeListener<RealmList<Weapon>>() {
@Override
public void onChange(RealmList<Weapon> weapons) {
/* Gives the adaptor a kick to know that the weapon realm list has changed */
attackListViewContentAdapter.notifyDataSetChanged();
loopOnChanged++;
}
});
lv_attack_spellcasting_title.setAdapter(attackListViewContentAdapter);
playerInit();
return rootView;
}
// This is a fake method, this is just to show that the .add is in it's own method which is triggered by a button press and not in onCreate
public void buttonPress() {
sheet.getWeaponList().add(realm.createObject(Weapon.class));
}
} `
public class AttackListViewContentAdapter extends ArrayAdapter<Weapon> {
public AttackListViewContentAdapter(Context context, Sheet sheet, Realm realm, List<Weapon> weaponList) {
super(context, 0, weaponList);
this.sheet = sheet;
this.realm = realm;
}
@Override
@NonNull
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
//Because you're returning the view (AttachToRoot is false) the ArrayAdaptor (This class) will handle adding the view to the list.
convertView =
LayoutInflater.from(getContext()).inflate(R.layout.attack_list_item, parent, false);
return convertView;
}
}
public class Weapon extends RealmObject {
@PrimaryKey
int weaponID;
//properties, set get methods etc.
}
public class Sheet extends RealmObject {
@PrimaryKey
private int sheetID;
private RealmList<Weapon> weaponList;
public RealmList<Weapon> getWeaponList() {
return weaponList;
}
public void setWeaponList(RealmList<Weapon> weaponList) {
this.weaponList = weaponList;
}
}
<ListView
android:id="@+id/lv_attack_spellcasting_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnCount="7"
android:rowCount="1" />
里面什么都没有
您的问题是由于 AttackListViewContentAdapter
class.
中的微调器小部件初始化错误所致
- 您必须在设置
setOnItemSelectedListener
之前设置微调器选择。
- 您必须检查您的微调器选择是否不等于当前选择,以避免
onChange
和 onItemSelected
方法之间的无限循环。我的意思是,你的 spinners onItemSelected
回调,执行一个领域交易,然后,这些交易触发你的 onChange
回调,最后,你的 onChange
回调调用 notifyDataSetChanged()
使循环再次开始进入无限循环。
要解决您的问题,您应该按照 AttackListViewContentAdapter.java:
中的后续步骤操作
A) 从 addWeaponToUI()
方法中删除以下行:
private void addWeaponToUI() {
et_name_value.setText(weapon.getWeaponName());
np_damage_number_of_die_value.setValue(weapon.getWeaponDamageNumberOfDie());
SheetEnum.Ability ability = SheetEnum.Ability.getEnumValue(weapon.getWeaponAbilityBonusInt());
tv_attack_bonus_value.setText(String.valueOf(sheet.getAbilityBonus(ability)));
// REMOVE below lines!
//s_damage_die_type_value.setSelection(weapon.getWeaponDamageDieTypeInt());
//s_damage_type_value.setSelection(weapon.getWeaponDamageTypeInt());
//s_ability_bonus_value.setSelection(weapon.getWeaponAbilityBonusInt());
}
B) 在 setOnItemSelectedListener()
之前调用微调器 setSelection()
,然后检查所选项目是否不等于所选位置以避免无限循环:
ArrayAdapter<CharSequence> damageDieTypeAdapter = ArrayAdapter.createFromResource(getContext(), R.array.die_type, android.R.layout.simple_spinner_dropdown_item);
s_damage_die_type_value.setAdapter(damageDieTypeAdapter);
//Set selection before listener
s_damage_die_type_value.setSelection(weapon.getWeaponDamageDieTypeInt());
s_damage_die_type_value.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View v, final int position, long id) {
//Check selected position is not equal to current position to avoid an infinite loop
if (position != weapon.getWeaponDamageDieTypeInt()) {
String[] value = getContext().getResources().getStringArray(R.array.die_type);
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
weapon.setWeaponDamageDieType(position);
}
});
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
C) 对 s_damage_type_value
和 s_ability_bonus_value
微调器重复 步骤 B
如果解释得不好,我深表歉意,我自己也很难理解。如果您指出任何您不理解的地方,我会尽力纠正任何问题。好的,我们开始吧。
几个类。 (D&D sheet, sheet 有用户可以装备的武器,这是关于装备存储在列表中的所述武器)
- 片段activity - CombatFragment
- 在CombatFragment中声明的arrayadapter列表 - AttackListViewContentAdapter
- 领域对象 - Weapon
- 持有武器列表的领域对象 - Sheet
- 一些XML个文件(我不会在这里粘贴的代码因为SO有代码限制。content_combat, attack_list_item
到目前为止我收集到的是,当我创建一个新的 attackListViewContentAdapter 时,它会以快速且持续的速度循环。如此之多,以至于屏幕对我触摸任何小部件都没有反应。我做了一些事情,比如每次通过时记录一个数字,这样它就会一次又一次地显示出来。如果您需要这方面的信息,我可以告诉您我将日志放在哪里以及在我添加其他视图(行)时 Logcat 中显示的内容。
我相信这与一直被触发的 onChangedListener 有关变化。
为了 space 的利益,请注意我将使用缩写代码。我忽略了不相关的对话框和小部件之类的东西。因此,如果它似乎缺少某些东西或者您需要查看 类,它可能在我在每个文件上方链接的文件中。
public class CombatFragment extends Fragment {
@BindView(R.id.lv_attack_spellcasting_content)
ListView lv_attack_spellcasting_title;
@Nullable
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.content_combat, container, false);
RealmList<Weapon> weaponList = sheet.getWeaponList();
final AttackListViewContentAdapter attackListViewContentAdapter = new AttackListViewContentAdapter(getActivity(), sheet, realm, weaponList);
weaponList.addChangeListener(new RealmChangeListener<RealmList<Weapon>>() {
@Override
public void onChange(RealmList<Weapon> weapons) {
/* Gives the adaptor a kick to know that the weapon realm list has changed */
attackListViewContentAdapter.notifyDataSetChanged();
loopOnChanged++;
}
});
lv_attack_spellcasting_title.setAdapter(attackListViewContentAdapter);
playerInit();
return rootView;
}
// This is a fake method, this is just to show that the .add is in it's own method which is triggered by a button press and not in onCreate
public void buttonPress() {
sheet.getWeaponList().add(realm.createObject(Weapon.class));
}
} `
public class AttackListViewContentAdapter extends ArrayAdapter<Weapon> {
public AttackListViewContentAdapter(Context context, Sheet sheet, Realm realm, List<Weapon> weaponList) {
super(context, 0, weaponList);
this.sheet = sheet;
this.realm = realm;
}
@Override
@NonNull
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
//Because you're returning the view (AttachToRoot is false) the ArrayAdaptor (This class) will handle adding the view to the list.
convertView =
LayoutInflater.from(getContext()).inflate(R.layout.attack_list_item, parent, false);
return convertView;
}
}
public class Weapon extends RealmObject {
@PrimaryKey
int weaponID;
//properties, set get methods etc.
}
public class Sheet extends RealmObject {
@PrimaryKey
private int sheetID;
private RealmList<Weapon> weaponList;
public RealmList<Weapon> getWeaponList() {
return weaponList;
}
public void setWeaponList(RealmList<Weapon> weaponList) {
this.weaponList = weaponList;
}
}
<ListView
android:id="@+id/lv_attack_spellcasting_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnCount="7"
android:rowCount="1" />
里面什么都没有
您的问题是由于 AttackListViewContentAdapter
class.
- 您必须在设置
setOnItemSelectedListener
之前设置微调器选择。 - 您必须检查您的微调器选择是否不等于当前选择,以避免
onChange
和onItemSelected
方法之间的无限循环。我的意思是,你的 spinnersonItemSelected
回调,执行一个领域交易,然后,这些交易触发你的onChange
回调,最后,你的onChange
回调调用notifyDataSetChanged()
使循环再次开始进入无限循环。
要解决您的问题,您应该按照 AttackListViewContentAdapter.java:
中的后续步骤操作A) 从 addWeaponToUI()
方法中删除以下行:
private void addWeaponToUI() {
et_name_value.setText(weapon.getWeaponName());
np_damage_number_of_die_value.setValue(weapon.getWeaponDamageNumberOfDie());
SheetEnum.Ability ability = SheetEnum.Ability.getEnumValue(weapon.getWeaponAbilityBonusInt());
tv_attack_bonus_value.setText(String.valueOf(sheet.getAbilityBonus(ability)));
// REMOVE below lines!
//s_damage_die_type_value.setSelection(weapon.getWeaponDamageDieTypeInt());
//s_damage_type_value.setSelection(weapon.getWeaponDamageTypeInt());
//s_ability_bonus_value.setSelection(weapon.getWeaponAbilityBonusInt());
}
B) 在 setOnItemSelectedListener()
之前调用微调器 setSelection()
,然后检查所选项目是否不等于所选位置以避免无限循环:
ArrayAdapter<CharSequence> damageDieTypeAdapter = ArrayAdapter.createFromResource(getContext(), R.array.die_type, android.R.layout.simple_spinner_dropdown_item);
s_damage_die_type_value.setAdapter(damageDieTypeAdapter);
//Set selection before listener
s_damage_die_type_value.setSelection(weapon.getWeaponDamageDieTypeInt());
s_damage_die_type_value.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View v, final int position, long id) {
//Check selected position is not equal to current position to avoid an infinite loop
if (position != weapon.getWeaponDamageDieTypeInt()) {
String[] value = getContext().getResources().getStringArray(R.array.die_type);
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
weapon.setWeaponDamageDieType(position);
}
});
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
C) 对 s_damage_type_value
和 s_ability_bonus_value
微调器重复 步骤 B