Home > Back-end >  Listener from DialogFragment to Fragment
Listener from DialogFragment to Fragment

Time:07-08

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?

CodePudding user response:

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 :)

  • Related