I am an android noob.
My Main Activity contains a recycler view which lists all the lessons booked by the user/student. Data comes from SQLite DB. When the user clicks on one of these lessons, a new activity (LessonInfo) shows its details and – only of it is in a certain status (“prenotato”, i.e. booked) – the user can change its status by pressing two different buttons.
I’m trying to update the recycler view inside my MainActivity after the uses presses one of these buttons. For the moment, the view is updated on every onResume and every time featching all data from the DB.
Main Activity --> LessonInfo -->Main Activity Updated
I would like 1) to get data only if the user changes the status of one lesson, and 2) to update only the holder of that specific lesson, using its position. I’ve tried several times but I’m locked...
Thanks a lot
Main Activity
public class MainActivity extends AppCompatActivity implements LessonsRecyclerAdapter.ClickInterface{
private TextView textViewName;
private RecyclerView recyclerViewLessons;
private ArrayList<Lezioni> lezioni;
private DatabaseHelper db;
private Studenti studente;
private LessonsRecyclerAdapter lessonsRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initObjects();
}
private void initViews() {
textViewName = findViewById(R.id.textViewName);
recyclerViewLessons = (RecyclerView) findViewById(R.id.recyclerViewLessons);
}
private void initObjects() {
lezioni = new ArrayList<>();
lessonsRecyclerAdapter = new LessonsRecyclerAdapter(lezioni, this, this);
db = new DatabaseHelper(MainActivity.this);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerViewLessons.setLayoutManager(mLayoutManager);
recyclerViewLessons.setHasFixedSize(true);
recyclerViewLessons.setAdapter(lessonsRecyclerAdapter);
Gson gson = new Gson();
studente = gson.fromJson(getIntent().getStringExtra("studente"), Studenti.class);
textViewName.setText(studente.getNome_st());
getLessonsFromSQLite();
}
@SuppressLint("NotifyDataSetChanged")
private void getLessonsFromSQLite() {
Executor executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
lezioni.clear();
lezioni.addAll(db.readLezioni(studente.getMatricola()));
handler.post(() -> lessonsRecyclerAdapter.notifyDataSetChanged());
});
}
public void onItemClick(int positionOfLesson){
Intent intent = new Intent(this, LessonInfo.class);
intent.putExtra("id_lezione", lezioni.get(positionOfLesson).getId_lezione());
startActivity(intent);
}
@Override
protected void onResume() {
super.onResume();
getLessonsFromSQLite();
}
LessonsRecyclerAdapter
public class LessonsRecyclerAdapter extends RecyclerView.Adapter<LessonsRecyclerAdapter.LessonsViewHolder> {
ArrayList<Lezioni> lezioni;
Context context;
ClickInterface clickInterface;
public LessonsRecyclerAdapter(ArrayList<Lezioni> lezioni, Context context, ClickInterface clickInterface) {
this.lezioni = lezioni;
this.context = context;
this.clickInterface = clickInterface;
}
@NonNull
@Override
public LessonsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item_lessons_recycler, parent, false);
return new LessonsViewHolder(itemView);
}
@Override
public void onBindViewHolder(LessonsViewHolder holder, int position) {
DatabaseHelper db = new DatabaseHelper(context);
Materie materia = db.getMateriaFromDB(db.getDocenteFromDB(lezioni.get(position).getId_docente()).getId_materia());
holder.textViewInsegnamento.setText(materia.getNome_materia());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
holder.textViewData.setText(lezioni.get(position).getParsedData().toLocalDate().format(formatter));
holder.textViewStato.setText(lezioni.get(position).getStato_lezione()); if(lezioni.get(position).getStato_lezione().equals("disdetta")){
holder.textViewStato.setTextColor(ContextCompat.getColor(context, R.color.yellow));
}else if(lezioni.get(position).getStato_lezione().equals("frequentata")){
holder.textViewStato.setTextColor(ContextCompat.getColor(context, R.color.green));
}else{
holder.textViewStato.setTextColor(ContextCompat.getColor(context, R.color.color_text));
}
}
@Override
public int getItemCount() {
Log.v(LessonsRecyclerAdapter.class.getSimpleName(),""+lezioni.size());
return lezioni.size();
}
public class LessonsViewHolder extends RecyclerView.ViewHolder {
AppCompatTextView textViewInsegnamento;
AppCompatTextView textViewData;
AppCompatTextView textViewStato;
public LessonsViewHolder(View view) {
super(view);
textViewInsegnamento = (AppCompatTextView) view.findViewById(R.id.textViewInsegnamento);
textViewData = (AppCompatTextView) view.findViewById(R.id.textViewData);
textViewStato = (AppCompatTextView) view.findViewById(R.id.textViewStato);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clickInterface.onItemClick(getAdapterPosition());
}
});
}
}
public interface ClickInterface{
void onItemClick(int positionOfLesson);
}
LessonsInfo
public class LessonInfo extends AppCompatActivity {
private TextView txtGiorno, txtOra, txtMateria, txtDocente;
private DatabaseHelper db;
private ConstraintLayout lessonContainer;
private Lezioni lezione;
private Docenti docente;
private Materie materia;
private LinearLayout interactiveButtons;
private Button btnCancel, btnConfirm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lesson_info);
initViews();
initObjects();
txtGiorno.setText(lezione.getData().split(" ")[0]);
txtOra.setText(String.format(getString(R.string.from_to_time), lezione.getFromTime(), lezione.getToTime()));
txtMateria.setText(materia.getNome_materia());
txtDocente.setText(docente.getNome_doc());
switchView();
}
private void initViews() {
lessonContainer = findViewById(R.id.lessonContainer);
txtGiorno = findViewById(R.id.txtGiorno);
txtOra = findViewById(R.id.txtOra);
txtMateria = findViewById(R.id.txtMateria);
txtDocente = findViewById(R.id.txtDocente);
interactiveButtons = findViewById(R.id.interactiveButtons);
}
private void switchView(){
GradientDrawable drawable = (GradientDrawable) lessonContainer.getBackground();
if(lezione.getStato_lezione().equals("disdetta")){
TextView txtStatus = findViewById(R.id.txtStatus);
drawable.setStroke(4, ContextCompat.getColor(this,R.color.primary));
txtStatus.setVisibility(View.VISIBLE);
interactiveButtons.setVisibility(View.GONE);
}else if(lezione.getStato_lezione().equals("frequentata")){
LinearLayout lessonFrequented = findViewById(R.id.lessonFrequented);
drawable.setStroke(4, ContextCompat.getColor(this,R.color.green));
lessonFrequented.setVisibility(View.VISIBLE);
interactiveButtons.setVisibility(View.GONE);
}else{
btnCancel = findViewById(R.id.btnCancel);
btnConfirm = findViewById(R.id.btnConfirm);
interactiveButtons.setVisibility(View.VISIBLE);
drawable.setStroke(4, ContextCompat.getColor(this,R.color.gray));
setOnClickListeners();
}
}
private void initObjects() {
db = new DatabaseHelper(getApplicationContext());
lezione = db.getLezioneFromDB(getIntent().getIntExtra("id_lezione", 0));
docente = db.getDocenteFromDB(lezione.getId_docente());
materia = db.getMateriaFromDB(docente.getId_materia());
}
private void setOnClickListeners(){
btnCancel.setOnClickListener(view -> {
lezione.setStato_lezione("disdetta");
if(db.updateStatoLezione(lezione)){
LessonInfo.this.recreate();
}else{
Toast.makeText(LessonInfo.this, "ERROR", Toast.LENGTH_SHORT).show();
}
});
btnConfirm.setOnClickListener(view -> {
lezione.setStato_lezione("frequentata");
if(db.updateStatoLezione(lezione)){
LessonInfo.this.recreate();
}else{
Toast.makeText(LessonInfo.this, "ERROR", Toast.LENGTH_SHORT).show();
}
});
}
UPDATE - SOLVED
Thank to Taranmeet Singh I've been able to find a way to accomplish my goal.
I first tried the simplest approach using startActivityForResult()
(DEPRECATED) and notifyItemChanged()
.
I than noticied I had to make some changes to the onClickListeners inside LessonsInfo: instead of recreating the activity I now recall a function (switchView()
) witch just modifies the appearence.
In order to let the user see the changes inside the LessonInfo activity (without going automatically back to the MainActivity), I just used a boolean isLessonUpdated
as a flag within the function onBackPressed()
: as the user goes back to the previous activity, if and only if he has changed the status of the lesson, I set the result of the Intent.
Lastly, I replaced the deprecated function registerForActivityResult()
with registerForActivityResult
, changing the onItemClick inside the main activity accordingly.
This is the code I came up with. No relevant changes have been applied to LessonRecyclerAdapter.java. Feel free to suggest improvements.
New MainActivity
public class MainActivity extends AppCompatActivity implements LessonsRecyclerAdapter.ClickInterface{
private TextView textViewName;
private RecyclerView recyclerViewLessons;
private ArrayList<Lezioni> lezioni;
private DatabaseHelper db;
private Studenti studente;
int positionClicked;
int idClicked;
private LessonsRecyclerAdapter lessonsRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initObjects();
}
private void initViews() {
textViewName = findViewById(R.id.textViewName);
recyclerViewLessons = findViewById(R.id.recyclerViewLessons);
}
private void initObjects() {
lezioni = new ArrayList<>();
lessonsRecyclerAdapter = new LessonsRecyclerAdapter(lezioni, this, this);
db = new DatabaseHelper(MainActivity.this);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerViewLessons.setLayoutManager(mLayoutManager);
recyclerViewLessons.setHasFixedSize(true);
recyclerViewLessons.setAdapter(lessonsRecyclerAdapter);
Gson gson = new Gson();
studente = gson.fromJson(getIntent().getStringExtra("studente"), Studenti.class);
textViewName.setText(studente.getNome_st());
getLessonsFromSQLite();
}
@SuppressLint("NotifyDataSetChanged")
private void getLessonsFromSQLite() {
Executor executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
lezioni.clear();
lezioni.addAll(db.readLezioni(studente.getMatricola()));
handler.post(() -> lessonsRecyclerAdapter.notifyDataSetChanged());
});
}
public void onItemClick(int positionOfLesson){
idClicked = lezioni.get(positionOfLesson).getId_lezione();
positionClicked = positionOfLesson;
Intent intent = new Intent(this, LessonInfo.class);
intent.putExtra("id_lezione", lezioni.get(positionClicked).getId_lezione());
LessonResultLauncher.launch(intent);
}
ActivityResultLauncher<Intent> LessonResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
lezioni.set(positionClicked, db.getLezioneFromDB(idClicked));
lessonsRecyclerAdapter.notifyItemChanged(positionClicked);
}
}
});
New LessonInfo
public class LessonInfo extends AppCompatActivity {
private TextView txtGiorno, txtOra, txtMateria, txtDocente;
private DatabaseHelper db;
private ConstraintLayout lessonContainer;
private Lezioni lezione;
private Docenti docente;
private Materie materia;
private LinearLayout interactiveButtons;
private Button btnCancel, btnConfirm;
private Boolean isLessonUpdated = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lesson_info);
initViews();
initObjects();
txtGiorno.setText(lezione.getData().split(" ")[0]);
txtOra.setText(String.format(getString(R.string.from_to_time), lezione.getFromTime(), lezione.getToTime()));
txtMateria.setText(materia.getNome_materia());
txtDocente.setText(docente.getNome_doc());
switchView();
}
private void initViews() {
lessonContainer = findViewById(R.id.lessonContainer);
txtGiorno = findViewById(R.id.txtGiorno);
txtOra = findViewById(R.id.txtOra);
txtMateria = findViewById(R.id.txtMateria);
txtDocente = findViewById(R.id.txtDocente);
interactiveButtons = findViewById(R.id.interactiveButtons);
}
private void switchView(){
GradientDrawable drawable = (GradientDrawable) lessonContainer.getBackground();
if(lezione.getStato_lezione().equals("disdetta")){
TextView txtStatus = findViewById(R.id.txtStatus);
drawable.setStroke(4, ContextCompat.getColor(this,R.color.primary));
txtStatus.setVisibility(View.VISIBLE);
interactiveButtons.setVisibility(View.GONE);
}else if(lezione.getStato_lezione().equals("frequentata")){
LinearLayout lessonFrequented = findViewById(R.id.lessonFrequented);
drawable.setStroke(4, ContextCompat.getColor(this,R.color.green));
lessonFrequented.setVisibility(View.VISIBLE);
interactiveButtons.setVisibility(View.GONE);
}else{
btnCancel = findViewById(R.id.btnCancel);
btnConfirm = findViewById(R.id.btnConfirm);
interactiveButtons.setVisibility(View.VISIBLE);
drawable.setStroke(4, ContextCompat.getColor(this,R.color.gray));
setOnClickListeners();
}
}
private void initObjects() {
db = new DatabaseHelper(getApplicationContext());
lezione = db.getLezioneFromDB(getIntent().getIntExtra("id_lezione", 0));
docente = db.getDocenteFromDB(lezione.getId_docente());
materia = db.getMateriaFromDB(docente.getId_materia());
}
private void setOnClickListeners(){
btnCancel.setOnClickListener(view -> {
lezione.setStato_lezione("disdetta");
if(db.updateStatoLezione(lezione)){
isLessonUpdated = true;
switchView();
}else{
Toast.makeText(LessonInfo.this, "ERROR", Toast.LENGTH_SHORT).show();
}
});
btnConfirm.setOnClickListener(view -> {
lezione.setStato_lezione("frequentata");
if(db.updateStatoLezione(lezione)){
isLessonUpdated = true;
switchView();
}else{
Toast.makeText(LessonInfo.this, "ERROR", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onBackPressed() {
Intent intent = new Intent();
if(isLessonUpdated){
Log.d("FLAG", "TRUE");
setResult(RESULT_OK, intent);
}
finish();
}
For your first question "to get data only if the user changes the status of one lesson" you can call the LessonInfo Activity using the registerForActivityResult()
from the MainActivity this way you can pass a result back that can be a boolean or any flag that tells MainActivity if there is any change. Check this docs for more details.
For your second question "to update only the holder of that specific lesson, using its position" you need to use the notifyItemChanged()
method of recycler view adapter to only update UI of 1 item and let the others remain same. Check this docs for updating one item.