Как отслеживать изменения данных по фрагментам? - PullRequest
0 голосов
/ 09 апреля 2020

У меня есть приложение, в котором у меня есть одно действие (основное), и там в макете у меня есть ViewPager2. Адаптер ViewPager2 имеет 2 фрагмента. Давайте назовем один из них как Фрагмент А.

Когда Фрагмент А открывается, пользователи имеют возможность открыть другой фрагмент, Фрагмент Б, изнутри себя. (по транзакции; у меня есть пустой FrameLayout внутри фрагмента A). Фрагмент B предоставляет диалоговое окно для редактирования данных, отображаемых с помощью RecyclerView во фрагменте A. Сам фрагмент A также имеет несколько параметров для изменения данных в своем RecyclerView.

Эти данные заполняются из общих настроек. Теперь проблема в том, что фрагменты можно связать только с действием с интерфейсами, я могу сохранить данные в действии, но тогда у меня нет другого выбора, кроме как перезагрузить весь RecyclerView во фрагменте A, поскольку фрагмент A не Не знаю, на каком месте он получил новые данные.

Пожалуйста, советуйте. Ниже приведены фрагменты и активность, которые я упомянул.

MainActivity. java:

package com.coffeetech.kittycatch;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements FoodEditorFragment.SendFoodFromEditor{
    ViewPager2 viewPager;
    TabLayout tab_menu;
    SwipeAdapter adapter;

    ArrayList<Food> foods;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewPager=findViewById(R.id.viewpager);
        adapter=new SwipeAdapter(this);
        viewPager.setAdapter(adapter);

        //SETTING TABS
        tab_menu = findViewById(R.id.tab_menu);
        new TabLayoutMediator(tab_menu, viewPager, true, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                switch(position){
                    case 0:
                        tab.setText("INVENTORY");
                        break;
                    case 1:
                        tab.setText("SHOPPING LIST");
                }
            }
        }).attach();



    }

    @Override
    public void onBackPressed() {
        super.onBackPressed(); //TODO: CONFIGURE THIS
    }

    @Override
    public void sendFood(Food food, int position) { //TODO: CODE TO REPLACE DATA TO SPECIFIC POSITION
        loadData();


        saveData();
    }

    @Override
    public void sendFood(Food food) { //TODO: CODE TO ADD DATA TO POSITION 0
        loadData();


        saveData();
    }

    public void loadData(){
        //TODO: LOAD THE LIST HERE
    }

    public void saveData(){
        //TODO: SAVE THE DATA HERE
    }
}

FragmentStateAdapter для ViewPager2:

package com.coffeetech.kittycatch;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;

public class SwipeAdapter extends FragmentStateAdapter {

    Fragment fragment;

    public SwipeAdapter(FragmentActivity fa){
        super(fa);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position){
            case 0: //START INVENTORY FRAGMENT
                fragment = new InventoryFragment();
                break;

            case 1: //START SHOPPING LIST FRAGMENT
                fragment = new ShoppingListFragment();
                break;
        }
        return fragment;

    }

    @Override
    public int getItemCount() {
        return 2;
    }
}

Фрагмент 'A':

package com.coffeetech.kittycatch;

import android.content.Context;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;

public class InventoryFragment extends Fragment {

    //GLOBAL VARIABLES
    RecyclerView recyclerView;
    FoodAdapter foodAdapter;
    ArrayList<Food> foods = new ArrayList<Food>();
    FloatingActionButton add_button;
    FrameLayout frameLayout;
    Food food;
    int q; //for use in decrease and functions

    public InventoryFragment() {
        // Required empty public constructor
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onPause() { //TODO:CODE TO SAVE DATA
        saveData();
        super.onPause();
    }

    @Override
    public void onResume() { //TODO:CODE TO LOAD DATA
        loadData();
        super.onResume();
        //food constructor takes arguments -> (String name, int type, int quantity, int min_quantity)
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View v = inflater.inflate(R.layout.fragment_inventory, container, false);
        foodAdapter = new FoodAdapter(foods);
        recyclerView=v.findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setAdapter(foodAdapter);

       //setting up the frameLayout
        frameLayout = v.findViewById(R.id.food_editor_frame);
        //setting up the Add button
        add_button=v.findViewById(R.id.add_button);
        add_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {  //for new food addition to list
                openFoodEditorFragment();
            }
        });

        foodAdapter.setOnFoodcardClickListener(new FoodAdapter.OnFoodcardClickListener() {
            @Override
            public void deleteFood(int position) { //code that deletes current food
                foods.remove(position);
                foodAdapter.notifyItemRemoved(position);
            }

            @Override
            public void onEdit(int position, int mode) { //code that runs the edit of each food, mode=1 for edit
                openFoodEditorFragment(position,foods.get(position)); //TODO: SEE IF YOU NEED 'mode' AT ALL
            }


            @Override
            public void decrease(int position) {
                food = foods.get(position);
                q=food.getQuantity();
                food.setQuantity(q-1);
                foodAdapter.notifyItemChanged(position);
            }

            @Override
            public void increase(int position) {
                food = foods.get(position);
                q=food.getQuantity();
                food.setQuantity(q+1);
                foodAdapter.notifyItemChanged(position);
            }

            @Override
            public void setSeekBar(int position,int progress) {
                food = foods.get(position);
                food.setQuantity(progress);
                Toast.makeText(getContext(),"Quantity set to "+progress+"%",Toast.LENGTH_SHORT).show();
                foodAdapter.notifyItemChanged(position);
            }
        });
        return v;
    }

    public void openFoodEditorFragment(int position,Food food){ //code for Editor in Edit Old mode

        //creating new Bundle and passing each member data of 'food'
        Bundle bundle = new Bundle();
        bundle.putString("name",food.getName());
        bundle.putInt("type",food.getType());
        bundle.putInt("quantity",food.getQuantity());
        bundle.putInt("min_quantity",food.getMin_quantity());
        bundle.putInt("mode",1);
        bundle.putInt("position",position);

        //setting up arguments for Fragment
        FoodEditorFragment foodEditorFragment = new FoodEditorFragment();
        foodEditorFragment.setArguments(bundle);

        //creating the Fragment
        FragmentTransaction transaction=getFragmentManager().beginTransaction();
        transaction.replace(R.id.food_editor_frame,foodEditorFragment);
        transaction.commit();
    }

    public void openFoodEditorFragment(){ //code for Editor in Add New mode

        //creating new Bundle and passing each member data of 'food'
        Bundle bundle = new Bundle();
        bundle.putInt("position",0);
        bundle.putInt("mode",0);

        //setting up arguments for Fragment
        FoodEditorFragment foodEditorFragment = new FoodEditorFragment();
        foodEditorFragment.setArguments(bundle);

        //creating the Fragment
        FragmentTransaction transaction=getFragmentManager().beginTransaction();
        transaction.replace(R.id.food_editor_frame,foodEditorFragment);
        transaction.commit();
    }


    protected void setData(int position, Food food){
        foods.remove(position);
        foods.add(position,food);
        foodAdapter.notifyItemChanged(position);
    }

    protected void setData(Food food){
        foods.add(0,food);
        foodAdapter.notifyItemInserted(0);
        Toast.makeText(getContext(),"Added to the top",Toast.LENGTH_SHORT).show();
    }

    void loadData(){
        //TODO: CODE TO LOAD DATA
    }

    void saveData(){
        //TODO: CODE TO SAVE DATA
    }
}

Фрагмент 'B':

package com.coffeetech.kittycatch;

import android.content.Context;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;


public class FoodEditorFragment extends Fragment {

    private TextView name,quantity,min_quantity;
    private ImageButton save,cancel;
    private RadioGroup radioGroup;

    protected int mode,t,position;
    protected Food food = new Food();

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        sffe = (SendFoodFromEditor)context;
    }

    public FoodEditorFragment() {
        // Required empty public constructor
    }

    public interface SendFoodFromEditor{
        void sendFood(Food food,int position); //FOR EDITING FOOD
        void sendFood(Food food); //FOR NEW FOOD
    }

    SendFoodFromEditor sffe;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_food_editor, container, false);
        name=view.findViewById(R.id.name_editor);
        quantity=view.findViewById(R.id.quantity_editor);
        min_quantity=view.findViewById(R.id.min_quantity_editor);
        save=view.findViewById(R.id.save_button_editor);
        cancel=view.findViewById(R.id.cancel_button_editor);
        radioGroup=view.findViewById(R.id.radioGroup_editor);

        mode=getArguments().getInt("mode");
        position=getArguments().getInt("position");

        if (mode==1){ //for editing Food
            //CODE TO SETUP EDITOR ACCORDING TO INITIAL DETAILS
            name.setText(getArguments().getString("name"));
            quantity.setText(String.valueOf(getArguments().getInt("quantity")));
            min_quantity.setText(String.valueOf(getArguments().getInt("min_quantity")));
            t=getArguments().getInt("type");

            if(t==0){//for discrete food
                radioGroup.check(R.id.discrete_radioButton);
            }else{//for cont food
                radioGroup.check(R.id.cont_radioButton);
            }

        }
        setButtons();
        return view;

    }


    public void setButtons(){
        save.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {  //USE BELOW 'food' TO PASS NEW DATA TO ACTIVITY
                 try {
                        if ((!name.getText().toString().isEmpty()) && ((radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) || (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton))) {
                            food.setName(name.getText().toString());
                            food.setQuantity(Integer.parseInt(quantity.getText().toString()));
                            food.setMin_quantity(Integer.parseInt(min_quantity.getText().toString()));

                            if (radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) {
                                food.setType(0);
                            } else if (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton) {
                                food.setType(1);
                            }
                            //CODE TO SEND THE FOOD TO ACTIVITY
                            if (mode == 1) {
                                sffe.sendFood(food, position);
                            } else {
                                sffe.sendFood(food);
                            }
                            //CLOSE THE FRAGMENT
                            getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
                        } else {
                            throw new Exception();
                        }
                    }catch (Exception e){
                        Toast.makeText(getContext(),"Please set all details",Toast.LENGTH_SHORT).show();
                    }
            }

        });

        cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { //CODE IF USER PRESSES ON CANCEL
                //CLOSE THE FRAGMENT
                getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
            }
        });
    }
}

1 Ответ

1 голос
/ 11 апреля 2020

Необходимо внести следующие изменения.

Во фрагменте A

Заменить

transaction.replace(R.id.food_editor_frame,foodEditorFragment);

на

transaction.add(R.id.food_editor_frame,foodEditorFragment);

Причина: использование replace удалит фрагмент A, а FragmentA всегда будет воссоздан.

В MainActivity

@Override
public void sendFood(Food food, int position){
//find fragment by Id
 Fragment fragmentA = (Fragment)
                    getSupportFragmentManager().findFragmentById(R.id.fragmetnA);

 fragment.setData(position,food)

      //code for save data here

}

 @Override
    public void sendFood(Food food) { 
        Fragment fragmentA = (Fragment)
                getSupportFragmentManager().findFragmentById(R.id.fragmetnA);

fragment.setData(food)

      //code for save data here

    }
...