Теперь я увидел, что вы сделали то, что я сказал в моем первом оригинальном ответе, я благодарю вас за это.
Кроме того, эта тема / сообщение может закончиться, поскольку вы уже реализовали onClick
для RecyclerView
. Буду признателен, если вы отметите мой ответ как решение.
Но, конечно, вы подняли еще одну проблему:
Я хочу добавить разные данные в каждый список элементов. но это происходит не для каждого списка элементов, которые загружаются в упражнении одинаковыми сохраненными данными ...
Это потому, что вы загружаете, а также сохраняете с помощью того же ключа :
editor.putString("text", json);
editor.apply();
Видите? Вы загружали и сохраняли на ключ "text"
в каждой теме. (Вы упомянули, что у вас есть список предметов, поэтому я использовал слово subject )
Я предлагаю вам создать средство для изменения ключа для каждого отдельного предмета. В этом случае имя вашего субъекта может быть ключевым вместо простого "text"
.
. Я также предлагаю вам использовать переменную private static final String
для "text"
, а также сделать ее более понятной. Ключ под названием "text"
немного двусмысленен, не правда ли?
Теперь я опубликую часть измененного кода вашего StudentListActivity
, я призываю вас проанализировать его и вставить в свой код. Я уверен, что теперь это будет работать.
Модифицированная часть в StudentListActivity
// Added a string variable here as key for saving/loading your data
String subName; // I kept your naming the same which is 'subName'
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.student_list);
// I placed this bit of code above loadData() now that we
// use subName as the key
// Or else loadData() will use the initial value of
// subName which is going to be null first
bundle = getIntent().getExtras();
subName = bundle.getString("Subject Name");
if (bundle != null) {
toolbar.setTitle(subName);setTitle(subName);
}
loadData();
toolbar = findViewById(R.id.toolbar);
fabButton();
buildRecyclerView();
}
// Other code... Which in your code are:
// private void buildRecyclerView() { ... }
// public void insertData(String text, String t1, String t2) { ... }
public void saveData() {
sharedPreferences = getSharedPreferences("SHARED PREF", MODE_PRIVATE);
editor = sharedPreferences.edit();
Gson gson = new Gson();
String json = gson.toJson(listOfNames);
// Now here use the name of your subject as key
// Which is of course the variable 'subName'
editor.putString(subName, json);
editor.apply();
}
public void loadData() {
sharedPreferences = getSharedPreferences("SHARED PREF", MODE_PRIVATE);
Gson gson = new Gson();
// Same here
// Use 'subName' as key
String json = sharedPreferences.getString(subName, null);
Type type = new TypeToken<ArrayList<ListOfNames>>() {
}.getType();
listOfNames = gson.fromJson(json, type);
if (listOfNames == null) {
listOfNames = new ArrayList<>();
}
}
// Other code ...
Кстати, я попытался сделать макеты самостоятельно, чтобы протестировать ваше приложение и я кое-что заметил: я думаю, у вас есть EditText
внутри вашего dialogbox_frontpage
. xml файла. И вы все еще написали код, чтобы получить представление к вашему ScrollingActivity
, который не нужен. Фактически, вы переопределили его в методе onClick
. Вы можете удалить эту переменную global
.
Последние примечания: Это всего лишь предложение, но вы можете попробовать и изучить шаблон Singleton
. Используйте этот шаблон для сохранения ваших данных. Кроме того, SharedPreferences
не очень хорошая идея, чтобы сохранить огромное количество данных. Поэтому я также призываю вас попытаться найти базы данных Room .
Я надеюсь, что ваша программа работает сейчас и, как всегда, удачного кодирования! (Это был очень длинный ответ, хахаха)
Оригинальный ответ (немного его изменил)
Я предлагаю создать interface
, который будет передать позицию элемента, по которому щелкнули, потому что мы заботимся только о позиции элемента, чтобы иметь возможность что-то с ним сделать. Кроме того, так лучше, чтобы мы могли добавить в действие код, который будет выполняться при нажатии на элемент.
Вот как должен выглядеть interface
:
public interface OnItemClickListener {
void onItemClick(int position);
}
Добавьте новый variable
внутри вашего adapter
, то есть OnItemClickListener
:
private OnItemCLickListener listener;
Вы можете либо определить его реализацию, внедрив его в действие, либо передать его реализацию, создав другой метод с именем addOnItemClickListener
в вашем adapter
:
addOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
Затем внутри вашего метода onBindViewHolder
получите макет элемента из ViewHolder
, установите его слушатель onClick
и, наконец, внутри метод onClick
, вызовите метод вашего интерфейса onItemClick
внутри него и передайте позицию там. Вот так:
@Override
public void onBindViewHolder(@NonNull CustomRecyclerView.ViewHolder holder, final int position) {
holder.layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.onItemClick(position);
}
});
}
Редактировать: Объяснение, почему я устанавливаю слушателя внутри метода onBindViewHolder
itemView
или View
, которые мы получаем от конструктора ViewHolder
, зависит от View
, возвращаемого LayoutInflater
внутри вашего onCreateViewHolder
. Следовательно, ресурс макета, который вы передаете в методе inflate
, независимо от того, какой основной макет вы там используете (например, ConstraintLayout
, LinearLayout
, это также может быть TextView
, Button
, et c.), Будет возвращено View
. Чтобы проверить это, попробуйте скопировать / вставить эту простую строку кода в onCreateViewHolder
, затем запустите ваше приложение и проверьте Logcat
:
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.YOUR_LAYOUT_HERE, parent, false);
Log.i("View", view.getClass().getSimpleName()); // Logs the main view in our layout
return new YourCustomViewHolderHere(view);
}
ViewHolder
только отвечает за получение наших представлений, потому что использование метода findViewById
является сложной задачей, если мы делаем это внутри onBindViewHolder
, поэтому мы не делаем это там, потому что это замедлит производительность нашего приложения.
Мы выполняем все настройки, такие как, например, изменение текста TextViews
или установка onClick
слушателей внутри onBindViewHolder
, чтобы избежать создания ненужной сложности в нашем коде. Мы не хотим, чтобы коды плавали вокруг, не так ли?
Кроме того, шаблон Observer весьма опасен .
Был разговор на конференции Android Я не помню, о чем говорилось RecyclerView
. Вы знаете, почему это так называется? Потому что это повторяет просмотров. (Требуется правильное объяснение того, как они перерабатывают представления, поэтому я не буду освещать это здесь. Я думаю, что вы можете найти его на YouTube, если будете искать "Android Conference RecyclerView" , это довольно долго, может быть, около часа, но это стоит посмотреть.)
Шаблон Observer (т. е. Listener) может вызвать утечки памяти, что повлияет на производительность нашего приложения. Следовательно, лучше установить его в нашем методе onBindViewHolder
, потому что всякий раз, когда мы прокручиваем вниз или вверх по нашему RecyclerView
, он перезапускает представления, и мы рискуем при создании множественных экземпляры того же слушателя внутри ViewHolder
.
Согласно Википедии о Шаблон наблюдателя :
Шаблон наблюдателя может вызвать утечки памяти, известные как проблема потерянного слушателя, потому что в реализации basi c она требует как явной регистрации, так и явной отмены регистрации, как в шаблоне dispose, потому что субъект держит сильные ссылки на наблюдателей, сохраняя их живыми. Это может быть предотвращено тем, что субъект держит слабые ссылки на наблюдателей.
Другой способ установить onClick
находится внутри onCreateViewHolder
, но выгода в том, что у вас нет способа узнать, какие элемент был нажат.
Надеюсь, это ответит на ваш вопрос в комментарии.