I'm a beginner in Java and I'm trying to create a listener in my DialogFragment
to notice my fragment that some book was removed. When the user removes a book, I want to call the removeBook method in BookFragment and update the recyclerview
.
Here is my BookDialogFragment.java:
package com.compose.dietapp.ui.books;
import android.app.Dialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import java.util.Objects;
public class BookDialogFragment extends DialogFragment {
private final String nameToDelete;
private final int position;
private static String MESSAGE_TO_DIALOG_FRAGMENT;
public BookDialogFragment(String nameToDelete, int position) {
this.nameToDelete = nameToDelete;
this.position = position;
}
public static BookDialogFragment newInstance(String title, String nameToDelete, int position) {
BookDialogFragment frag = new BookDialogFragment(nameToDelete, position);
if (Objects.equals(nameToDelete, "none")) {
MESSAGE_TO_DIALOG_FRAGMENT = "Book removed!";
} else {
MESSAGE_TO_DIALOG_FRAGMENT = "Are you sure you want to remove the book '"
+ nameToDelete
+ "'?";
}
Bundle args = new Bundle();
args.putString("title", title);
frag.setArguments(args);
return frag;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
assert getArguments() != null;
String title = getArguments().getString("title");
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setTitle(title);
alertDialogBuilder.setMessage(MESSAGE_TO_DIALOG_FRAGMENT);
if (Objects.equals(MESSAGE_TO_DIALOG_FRAGMENT, "Book removed!")) {
alertDialogBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (dialog != null) {
dialog.dismiss();
}
}
});
} else {
alertDialogBuilder.setPositiveButton("Remove", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// here I want to callback my fragment
BookFragment deleteBook = new BookFragment();
deleteBook.removeBook(nameToDelete, position);
Bundle result = new Bundle();
result.putBoolean("value", true);
getParentFragmentManager().setFragmentResult("removed", result);
}
});
alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (dialog != null) {
dialog.dismiss();
}
}
});
}
return alertDialogBuilder.create();
}
@Override
public void onStart() {
super.onStart();
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEGATIVE)
.setTextColor(Color.rgb(128, 128, 128));
}
}
And here is my BookFragment.java:
package com.compose.dietapp.ui.books;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.compose.dietapp.R;
import com.compose.dietapp.database.DatabaseAccess;
import com.compose.dietapp.databinding.FragmentBookBinding;
import java.util.ArrayList;
public class BookFragment extends Fragment{
@SuppressLint("StaticFieldLeak")
private static Activity activity;
private RecyclerView recyclerView;
private final ArrayList<Book> itensBook = new ArrayList<Book>();
private BookAdapter bookAdapter;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
activity = this.getActivity();
View v = inflater.inflate(R.layout.fragment_book, container, false);
recyclerView = (RecyclerView) v.findViewById(R.id.book_recycler);
instanciateBooks();
return v;
}
private void instanciateBooks() {
ArrayList<ArrayList<String>> bookDatabaseValues = getDatabaseData();
if (recyclerView != null && bookDatabaseValues != null) {
createItemBook(bookDatabaseValues);
createRecyclerViewBook();
}
}
public void removeBook(String nameToDelete, int position) {
getChildFragmentManager().setFragmentResultListener("removed",
this, new FragmentResultListener() {
@Override
public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) {
String result = bundle.getString("value");
Log.i("result", result);
}
});
}
private void createRecyclerViewBook() {
recyclerView.setHasFixedSize(true);
bookAdapter = new BookAdapter(activity, itensBook);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(activity,
LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(bookAdapter);
}
private void createItemBook(ArrayList<ArrayList<String>> bookDatabaseValues) {
for (int i = 0; i < bookDatabaseValues.size(); i++) {
itensBook.add(new Book(
String.valueOf(bookDatabaseValues.get(i).get(0)),
String.valueOf(bookDatabaseValues.get(i).get(1)),
String.valueOf(bookDatabaseValues.get(i).get(2)),
String.valueOf(bookDatabaseValues.get(i).get(3)),
String.valueOf(bookDatabaseValues.get(i).get(4))
));
}
}
public static ArrayList<ArrayList<String>> getDatabaseData() {
if (activity != null) {
return getArrayListsFromDatabase();
}
return null;
}
private static ArrayList<ArrayList<String>> getArrayListsFromDatabase() {
DatabaseAccess databaseAccess = openDatabase();
ArrayList<ArrayList<String>> books = databaseAccess.getBook();
closeDatabase(databaseAccess);
return books;
}
private static void closeDatabase(DatabaseAccess databaseAccess) {
databaseAccess.close();
}
@NonNull
private static DatabaseAccess openDatabase() {
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(activity);
databaseAccess.open();
return databaseAccess;
}
}
Here is my BookAdapter.java:
package com.compose.dietapp.ui.books;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
import com.compose.dietapp.R;
import java.io.InputStream;
import java.util.ArrayList;
public class BookAdapter extends RecyclerView.Adapter<BookViewHolder> {
public static FragmentManager supportFragment;
private final Context context;
private final ArrayList<Book> itens;
public BookAdapter(Context context, ArrayList<Book> itens) {
this.context = context;
this.itens = itens;
}
@NonNull
@Override
public BookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_recycler_book, parent, false);
BookViewHolder viewHolder = new BookViewHolder(view);
supportFragment = ((AppCompatActivity)context).getSupportFragmentManager();
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull BookViewHolder bookViewHolder, int position) {
Book book = itens.get(position);
bookViewHolder.nome.setText(book.getName());
bookViewHolder.bookType.setText(book.getBookType());
imageInstanciate(bookViewHolder);
}
private void imageInstanciate(@NonNull BookViewHolder bookViewHolder) {
new DownloadImageFromInternet((ImageView) bookViewHolder.bookImage)
.execute("https://pbs.twimg.com/profile_images/630285593268752384/iD1MkFQ0.png");
}
private class DownloadImageFromInternet extends AsyncTask<String, Void, Bitmap> {
ImageView imageView;
public DownloadImageFromInternet(ImageView imageView) {
this.imageView = imageView;
}
protected Bitmap doInBackground(String... urls) {
String imageURL = urls[0];
Bitmap bimage = null;
try {
InputStream in = new java.net.URL(imageURL).openStream();
bimage = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error Message", e.getMessage());
e.printStackTrace();
}
return bimage;
}
protected void onPostExecute(Bitmap result) {
imageView.setImageBitmap(result);
}
}
@Override
public int getItemCount() {
return itens.size();
}
}
Here is my BookViewHolder.java:
package com.compose.dietapp.ui.books;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
import com.compose.dietapp.R;
public class BookViewHolder extends RecyclerView.ViewHolder {
TextView nome;
TextView bookType;
ImageView bookImage;
public BookViewHolder(@NonNull View itemView) {
super(itemView);
nome = itemView.findViewById(R.id.nome);
bookType = itemView.findViewById(R.id.email);
bookImage = itemView.findViewById(R.id.book_image);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
int position = getLayoutPosition();
return true;
}
});
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String nomeDelete = nome.getText().toString();
int position = getLayoutPosition();
FragmentManager fm = BookAdapter.supportFragment;
BookDialogFragment bookDialogFragment =
BookDialogFragment.newInstance("Atenção:", nomeDelete, position);
bookDialogFragment.show(fm, "fragment_alert");
}
});
}
}
I've seen other similar solutions, but I didn't get to implement them in my code. Can anyone help me?
Going through your code, it doesn't seem like you're using Navigation Component. So let's do it this way.
Your BookDialogFragment is a child fragment to BookFragment. So basically, you should set a result in your dialog when remove button is clicked. Then set up a result listener code in you parent fragment (BookFragment), so as to get immediate result to act upon.
First part, set a result when remove is clicked
NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
if (Objects.equals(MESSAGE_TO_DIALOG_FRAGMENT, "Book removed!")) {
...
} else {
alertDialogBuilder.setPositiveButton("Remove", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// here I want to callback my fragment
BookFragment deleteBook = new BookFragment();
deleteBook.removeBook(nameToDelete, position);
Bundle result = new Bundle();
result.putBoolean("value", true);
getParentFragmentManager().setFragmentResult("removed", result);
}
});
alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
...
}
}
}
Then, listen for and act on the result in you BookFragment, wherever you want to, with these lines.
getChildFragmentManager().setFragmentResultListener("removed", this, new FragmentResultListener() {
@Override
public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle bundle) {
// We use a Boolean here, but any type that can be put in a Bundle is supported
Boolean result = bundle.getString("value");
// Do something with the result
}
});
PS: You can use constant variables where you have "removed" and "value" for accuracy.
Hope this helps :)