Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
87 views
in Technique[技术] by (71.8m points)

java - Create a RecylerView inside a Fragment without having setUp the Fragment in Android

I have a Fragment 'FR_MyItems' and inside it I create a RecyclerView 'myItemsRecyclerView' by using an ArrayList 'myItemsList'. When I navigate to the Fragment the RecyclerView the Fragment is created and the RecyclerView is set up and it works fine.

However, now I want to add items to this Recyclerview from another class by using the static method 'public static void insertItem(String ItemType, String ItemName)'. The problem is that if I have not navigated to the Frament 'FR_MyItems' before, the RecyclerView is not set up and I get a null pointer expection when trying to do something with the RecyclerView.

So my question now is how can I create this RecyclerView without having navigated to the Fragment that hosts it? In my initial class all the RecyclerView variables were not static but now I have to make them static such that I can access them from other classes.

Here you see the Java code of the 'FR_MyItems':

package com.example.td.bapp;

import android.content.res.Resources;
import android.os.Bundle;

import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.td.bapp.databinding.MyItemsBinding;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimeZone;


public class FR_MyItems extends Fragment {




    private static RecyclerView myItemsRecyclerView;
    private static MyItemsAdapter myItemsAdapter;
    private static RecyclerView.LayoutManager myItemsLayoutManager;

    private static ArrayList<MyItemsItem> myItemsList;

    public FR_MyItems() {

    }


    public static FR_MyItems newInstance(String param1, String param2) {
        FR_MyItems fragment = new FR_MyItems();
        Bundle args = new Bundle();

        fragment.setArguments(args);
        return fragment;
    }

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



    }


    private MyItemsBinding binding;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        binding = MyItemsBinding.inflate(inflater, container, false);
        createExampleList();
        buildRecyclerView();
        return binding.getRoot();

    }
    public void createExampleList () {
        myItemsList = new ArrayList<MyItemsItem>();
        myItemsList.add(new MyItemsItem(R.drawable.ic_android, "Item 1", "C", "20:34, 12.12.20"));
        myItemsList.add(new MyItemsItem(R.drawable.ic_android, "Item 2", "A", "21:34"));
        myItemsList.add(new MyItemsItem(R.drawable.ic_android, "Item 3", "B", "20:34"));
    }

    public  void buildRecyclerView () {
        myItemsRecyclerView = binding.recyclerView;
        myItemsRecyclerView.setHasFixedSize(true);
        myItemsLayoutManager = new LinearLayoutManager(this.getContext());
        myItemsAdapter = new MyItemsAdapter(myItemsList);

        myItemsRecyclerView.setLayoutManager(myItemsLayoutManager);
        myItemsRecyclerView.setAdapter(myItemsAdapter);

        myItemsAdapter.setOnItemClickListener(new MyItemsAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                changeItemStatus(position, "Clicked");
            }
        });
    }


    public static void insertItem(String ItemType, String ItemName) {

        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm z, dd-MM-yyyy");
        sdf.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
        int position =myItemsList.size();

        String status = "good";
        if(FR_LanguageSelection.currentLanguageOfTheApp.equals(FR_LanguageSelection.LANGUAGE_GERMAN)) {
            status = "gut";
        }

        if (ItemType.equals(DataBaseEntries.ITEM2)) {
            myItemsList.add(position, new MyItemsItem(R.drawable.ic_android, ItemName, status, sdf.format(new Date())));
            myItemsAdapter.notifyItemInserted(position);
        }

    }



    public void removeItem (int position) {
        myItemsList.remove(position);
        myItemsAdapter.notifyItemRemoved(position);

    }

    public void changeItemStatus (int position, String newStatus) {
        myItemsList.get(position).setStatusProperty(newStatus);
        myItemsAdapter.notifyItemChanged(position);
    }
}

I'd appreciate every comment and would be quite thankful for your help.

question from:https://stackoverflow.com/questions/65857722/create-a-recylerview-inside-a-fragment-without-having-setup-the-fragment-in-andr

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The question is not very clear but I will try to help you

As the others said it would be best for you to use Viewmodel, livedata and room. In the beginning it is a little difficult but later it is much easier and faster to work...

If you do not want to use the room, you may use the viewmodel to inform the fragments in the activity about changes

example:

  1. Create ViewModel class like this

     public class MyItemsViewModel extends AndroidViewModel {
    
         private final MutableLiveData<Boolean> refresh;
    
         public MyItemsViewModel(@NonNull Application application) {
             super(application);
             this.refresh  = new MutableLiveData<>();
         }
    
         public void setRefresh(Boolean ref) {
             this.refresh.setValue(ref);;
         }
    
         public MutableLiveData<Boolean> getRefresh() {
             return this.refresh;
         }
    
    
    
    
         public static class Factory extends ViewModelProvider.NewInstanceFactory {
    
             private final Application application;
    
             public Factory(@NonNull Application application) {
                 this.application = application;
             }
    
             @NonNull
             @Override
             public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                 //noinspection unchecked
                 return (T) new MyItemsViewModel(this.application);
             }
         }
    
     }
    

In Activity where is your FR_MyItems Fragment, (probably your main activity) copy/paste this code (only code below TODO in comment)

@Override
protected void onCreate(Bundle savedInstanceState) {
     //TODO copy this in onCreate method
     MyItemsViewModel.Factory factory = new MyItemsViewModel.Factory(getApplication());
     viewModel = new ViewModelProvider(this, factory).get(MyItemsViewModel.class);
     subscribe();
}

and copy/paste complete this method

private void subscribe() {
        viewModel.getRefresh().observe(this, refreshed -> {
            if(refreshed){
                Toast.makeText(this, "Refreshed", Toast.LENGTH_SHORT).show();
            }
        });
    }
  1. In FR_MyItems Frgament

copy this (compete function)

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if(getActivity() == null) return;
        MyItemsViewModel.Factory factory = new MyItemsViewModel.Factory(requireActivity().getApplication());
        viewModel = new ViewModelProvider(requireActivity(), factory).get(MyItemsViewModel.class);
        subscribe();
    }

    private void subscribe() {
        viewModel.getRefresh().observe(getViewLifecycleOwner(), refreshed -> {
            if(refreshed){
                //TODO load data from sqlite database and update your MyItemsAdapter with new data list 
                Toast.makeText(getContext(), "Refreshed Fragment", Toast.LENGTH_SHORT).show();
                viewModel.setRefresh(false);
            }
        });
    }
  1. In your fragment for creating new item (if exist)

copy this

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            if(getActivity() == null) return;
            MyItemsViewModel.Factory factory = new MyItemsViewModel.Factory(requireActivity().getApplication());
            viewModel = new ViewModelProvider(requireActivity(), factory).get(MyItemsViewModel.class); 
        }
    

And finaly when you insert new item do it

copy this in method after inserting

viewModel.setRefresh(true);

it will reload adata and refresh your list in FR_MyItems

Also if you don't want insert item in database you can create List myItemsList in MyItemsViewModel create get,set,add methods and observe it from fragments

Add this in class MyItemsViewModel

    private List<MyItemsItem>> items
    private final MutableLiveData<List<MyItemsItem>> myItemsList;
        public MyItemsViewModel(@NonNull Application application) {
            super(application);
            items= new ArrayList();
            this.refresh  = new MutableLiveData<>();
            this.myItemsList  = new MutableLiveData<>();
        }
    public addItem(MyItemsItem item){
            items.add(item);
            myItemsList.setValue(items);
        }
//TODO create set, get and add methods for list

and observe it in your activity or fragments

viewModel.getMyItemsList().observe(getViewLifecycleOwner(), list -> { 
    //TODO update adapter with list
});

Also you can use it on other way if you want use notifyItemChanged and don't want to swap data in adapter every time

This is possible in the activity and its fragments.

If you want to refresh the lists between activities you will have to use room or some other way to do so...

EDITED 2

This image is only for your case and it will be deleted soon

In other cases the data is managed (CRUD) through the ViewModel and repository or repositories not in View-UI

example


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...