Попытка получить обратные вызовы из DialogFragment во фрагмент, но приложение не работает - PullRequest
0 голосов
/ 07 декабря 2018

У моего приложения MainActivity есть ViewPager, у которого трое детей (пролистывание).При наведении на последнего ребенка, ActionBar получает два menu предмета.При нажатии на один элемент появляется Dialog, чтобы добавить имя элемента в Database.При нажатии на второй элемент menu появляется другое Dialog, которое предлагает пользователю ввести имя элемента, который должен быть удален из Database.Эти Dialogs создаются отдельными Dialog Fragments.По сути, я хочу получить событие callback от Dialog, когда была нажата положительная или отрицательная кнопка, и я хочу выполнить какое-то действие во фрагменте, который, как я уже говорил, является последним потомком моего ViewPager.Я видел документацию Android и видео с Youtube, чтобы узнать, как реализовать интерфейс, но мое приложение не работает.

Вот код для DialogFragment, который показывает Dialog который предлагает пользователю ввести ввод и сохранить его в Database.

package com.example.android.mybusiness;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class AddCigaretteNameDialog extends DialogFragment {

    EditText userInput;
    String cigaretteName;
    DbHelper dbHelper;

    public AddCigaretteNameDialogListener listener;

    public interface AddCigaretteNameDialogListener {
        void onDialogPositiveClick(String name);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        dbHelper = new DbHelper(getContext());

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        // SET THE TITLE FOR THE DIALOG.
        builder.setTitle(R.string.add_title);
        // GET THE LAYOUT INFLATOR
        LayoutInflater inflater = getActivity().getLayoutInflater();
        // INFLATE THE LAYOUT AND PUT IT INTO A VARIABLE.
        // PASS NULL AS PARENT VIEW, BECAUSE IT'S GOING IN THE DIALOG
        View view = inflater.inflate(R.layout.edit_text_for_dialogs, null);
        // GET THE EDIT_TEXT FROM THE 'VIEW' VARIABLE.
        userInput = view.findViewById(R.id.cigarette_name_user_input);
        // SET THE LAYOUT FOR THE DIALOG
        builder.setView(view);
        // SET ACTION BUTTONS
            builder.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    // GET THE USER INPUT FROM THE EDIT_TEXT ABOVE AND PUT IT INTO A VARIABLE.
                    cigaretteName = userInput.getText().toString();
                    // PUT THE USER INPUT IN THE DATABASE.
                    Boolean result = dbHelper.insertCigaretteName(cigaretteName);
                    if (result) {

                        // SHOW SUCCESS MESSAGE THAT CIGARETTE NAME HAS BEEN INSERTED.
                        Toast.makeText(getContext(), cigaretteName + " has been added successfully!", Toast.LENGTH_SHORT).show();

                        listener.onDialogPositiveClick(cigaretteName);



                    } else {Toast.makeText(getContext(), "Something is wrong", Toast.LENGTH_SHORT).show();}
                }
            })
            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    dismiss();
                }
            });



        // RETURN THE DIALOG.
        return builder.create();
    }


    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        // VERIFY THAT THE HOST ACTIVITY IMPLEMENTS THE CALLBACK INTERFACE
        try {
            listener = (AddCigaretteNameDialogListener) getTargetFragment();
        } catch (ClassCastException e){
            // THE ACTIVITY DOESN'T IMPLEMENT INTERFACE, THROW AN EXCEPTION.
            throw new ClassCastException(getActivity().toString() + " must implement listener");
        }

    }
}

А вот фрагмент, который является последним дочерним элементом пейджера вида.

package com.example.android.mybusiness;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;


/**
 * A simple {@link Fragment} subclass.
 */
public class Purchase extends Fragment implements AddCigaretteNameDialog.AddCigaretteNameDialogListener {
    Spinner spinner;
    DbHelper dbHelper;
    ArrayAdapter<String> arrayAdapter;



    // FRAGMENT'S CONSTRUCTOR.
    public Purchase() { }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // KIND OF REQUIREMENT FOR OPTION MENUS.
        setHasOptionsMenu(true);
        // INSTANTIATING THE OBJECT TO RUN A FUNCTION, WHICH GETS THE CIGARETTES NAME.
        dbHelper = new DbHelper(getContext());

        // Inflate the layout for this fragment
        // AND PUT IT INTO A VARIABLE SO WIDGETS CAN BE ACCESSED.
        View view = inflater.inflate(R.layout.fragment_purchase, container, false);
        // FIND THE spinner.
        spinner = view.findViewById(R.id.spinner);

        // CREATING THIS ADAPTER TO POPULATE THE SPINNER WIDGET.
        arrayAdapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, dbHelper.getAllCigaretteNames());

        // SETTING THE ADAPTER TO THE SPINNER, WHICH WILL PROVIDE THE CONTENT TO BE SELECTED BY ME.
        spinner.setAdapter(arrayAdapter);


        return view;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.add_cigarette:
                AddCigaretteNameDialog addCigaretteNameDialog = new AddCigaretteNameDialog();
                addCigaretteNameDialog.show(getFragmentManager(), "add_cigarette_name");
                return true;
            case R.id.remove_cigarette:
                RemoveCigaretteNameDailog RemoveCigaretteNameDailog = new RemoveCigaretteNameDailog();
                RemoveCigaretteNameDailog.show(getFragmentManager(), "add_cigarette_name");
            ;    return true;
            default:
                return super.onOptionsItemSelected(item);
        }

    }

    @Override
    public void onDialogPositiveClick(String name) {
        arrayAdapter.add(name);
    }
}

Вот журнал сбоев:

12-07 13: 13: 59.278 25327-25327 / com.example.android.mybusiness E / AndroidRuntime: ИСКЛЮЧИТЕЛЬНОЕ ИСКЛЮЧЕНИЕ: основной процесс: com.example.android.mybusiness, PID: 25327 java.lang.NullPointerException: попытка вызвать метод интерфейса void com.example.android.mybusiness.AddCigaretteNameDialog $ AddCigaretteNameDialogListener.lang.Ignog.ialg) 'для ссылки на пустой объект в com.example.android.mybusiness.AddCigaretteNameDialog $ 2.onClick (AddCigaretteNameDialog.java:58) в com.android.internal.app.AlertController $ ButtonHandler.handleMessage (AlertControlle)r.java:162) на android.os.Handler.dispatchMessage (Handler.java:102) на android.os.Looper.loop (Looper.java:135) на android.app.ActivityThread.main (ActivityThread.java:5296) в java.lang.reflect.Method.invoke (собственный метод) в java.lang.reflect.Method.invoke (Method.java:372) в com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java): 912) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:707)

Строка 58 -

слушатель.onDialogPositiveClick (сигаретное имя);

Заранее спасибо!

1 Ответ

0 голосов
/ 07 декабря 2018

Если вы используете настраиваемый класс диалога с настраиваемым представлением, это решит вашу проблему.Я размещаю код ниже, который показывает пользовательский диалог с представлениями.Прежде всего, создайте файл макета для вашего диалогового дизайна по имени dlg_add_cigarette_name внутри layout папки

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@drawable/dialog_background_inset"
android:layout_height="wrap_content">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:layout_marginLeft="16dp"
    android:text="Cigrate Name:"
    android:id="@+id/tv_label_total"
    />
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/layout_total_update"
    android:orientation="horizontal"
    android:layout_below="@+id/tv_label_total"
    android:weightSum="2"
    >
    <EditText
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1.5"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="10dp"
        android:id="@+id/et_cgrate_name"
        android:inputType="text"
        />
</LinearLayout>



<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/layout_total_update"
    android:layout_alignParentRight="true"
    android:background="@android:color/transparent"

    android:layout_marginRight="70dp"
    android:text="OK"
    android:layout_marginBottom="20dp"
    android:layout_marginTop="20dp"
    android:id="@+id/button_ok"
    android:textColor="@color/colorPrimaryDark"
    />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/layout_total_update"
    android:layout_toLeftOf="@+id/button_ok"
    android:layout_marginRight="30dp"
    android:text="Cancel"
    android:layout_marginBottom="20dp"
    android:layout_marginTop="20dp"
    android:background="@android:color/transparent"
    android:id="@+id/button_cancel"
    android:textColor="@color/colorPrimaryDark"
    />

Теперь внутри папки для рисования создайте новый файл по имени dialog_background_inset иобновите файл с помощью следующего кода

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@color/white"
    android:insetRight="15dp"
    android:insetLeft="15dp">
</inset>

и теперь в вашем файле AddCigaretteNameDialog обновите класс с помощью следующего кода

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.drinkwater.reminder.watertracker.R;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;


public class AddCigaretteNameDialog extends DialogFragment {
    private static final float DIM_AMOUNT = 0.4f;
    @BindView(R.id.tv_label_total)
    TextView tvLabelTotal;
    @BindView(R.id.et_cgrate_name)
    EditText etCgrateName;
    @BindView(R.id.layout_total_update)
    LinearLayout layoutTotalUpdate;
    @BindView(R.id.button_ok)
    Button buttonOk;
    @BindView(R.id.button_cancel)
    Button buttonCancel;

    @OnClick(R.id.button_cancel)
    public void onClick(){
        dismiss();
    }
    @OnClick(R.id.button_ok)
    public void onClickOkay(){
        unitCallBack.addCigarette(cigaretteName);
    }



    private Unbinder mUnbinder;
    private AddCigaretteName unitCallBack;

    private String cigaretteName;



    public AddCigaretteNameDialog() {
    }

    public static AddCigaretteNameDialog newInstance(String title) {
        AddCigaretteNameDialog frag = new AddCigaretteNameDialog();
        Bundle args = new Bundle();
        args.putString("title", title);
        frag.setArguments(args);
        return frag;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (unitCallBack == null && context instanceof AddCigaretteName) {
            unitCallBack = (AddCigaretteName) context;
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        unitCallBack = null;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final Dialog dialog = super.onCreateDialog(savedInstanceState);

        final Window window = dialog.getWindow();
        if (window != null) {
            window.requestFeature(Window.FEATURE_NO_TITLE);
            window.setBackgroundDrawableResource(android.R.color.transparent);

            WindowManager.LayoutParams windowLayoutParams = window.getAttributes();
            windowLayoutParams.dimAmount = DIM_AMOUNT;
        }
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);
        return dialog;
    }


    @SuppressLint("NewApi")
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.test, container, false);
        mUnbinder = ButterKnife.bind(this, view);

        etCgrateName.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

                cigaretteName=s.toString();
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        final int width = getScreenWidth();
        int height = getScreenHeight() / 2;
        changeWindowSizes(width, ViewGroup.LayoutParams.WRAP_CONTENT);
    }

    private void changeWindowSizes(int width, int height) {
        final Window window = getDialog().getWindow();
        if (window != null) {
            window.setLayout(width, height);
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mUnbinder.unbind();
    }

    @Override
    public int getTheme() {
        return R.style.CustomDialog;
    }

    public interface AddCigaretteName {
        void addCigarette(String name);
    }

    public static int getScreenWidth() {
        return Resources.getSystem().getDisplayMetrics().widthPixels;
    }

    public static int getScreenHeight() {
        return Resources.getSystem().getDisplayMetrics().heightPixels;
    }
}

создайте собственную тему внутри файла стилей

 <style name="CustomDialog" parent="Theme.AppCompat.Light.Dialog">
        <item name="android:windowAnimationStyle">@style/CustomDialogAnimation</item>
    </style>

    <style name="CustomDialogAnimation">
        <item name="android:windowEnterAnimation">@anim/translate_left_side</item>
        <item name="android:windowExitAnimation">@anim/translate_right_side</item>
    </style>

создайте пакет anim внутри res папки и создайте два файла translate_left_side и translate_right_side translate_right_side

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0%" android:toXDelta="100%"
    android:fromYDelta="0%" android:toYDelta="0%"
    android:duration="600"/>

translate_left_side

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="600"
    android:fromXDelta="100%"
    android:toXDelta="0%"/>

Ваш AddCigrateDialog готов к появлению. Теперь пора вызывать этот диалог нажатием кнопки. Внутри Purchase сделать объект класса AddCigaretteDialog глобально

AddCigaretteNameDialog addCigaretteNameDialog;

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.add_cigarette:
                 addCigaretteNameDialog= new AddCigaretteNameDialog();            
                 addCigaretteNameDialog= AddCigaretteNameDialog.newInstance("AddCigrateNameDialog");
                 addCigaretteNameDialog.show(manager,"show");
                return true;
            case R.id.remove_cigarette:
                RemoveCigaretteNameDailog RemoveCigaretteNameDailog = new RemoveCigaretteNameDailog();
                RemoveCigaretteNameDailog.show(getFragmentManager(), "add_cigarette_name");
            ;    return true;
            default:
                return super.onOptionsItemSelected(item);
        }

    }

И да, не забудьте реализовать интерфейс AddCigaretteDialog внутри Purchase диалогового окна

Поскольку я использую зависимость ButterKnife, добавьте следующие строки в файл gradle вашего приложения

inal BUTTER_KNIFE_VERSION = "8.8.1"
implementation "com.jakewharton:butterknife:$BUTTER_KNIFE_VERSION"
annotationProcessor "com.jakewharton:butterknife-compiler:$BUTTER_KNIFE_VERSION"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...