I'm using ViewPager2 and RecyclerView develop to Search activity.
What I want is use text entered in EditText as request parameter and response data is reflected in the RecyclerView.
I checked that the data was responded normally, but it was not reflected in the view.
I read so many questions and posts, but I couldn't solve the problem that the view was not refreshed.
Upon checking, data was added to the list of RecyclerView, the methods of the RecyclerView Adapter were not executed at all.
SearchActivity
public class SearchActivity extends AppCompatActivity {
private ActivitySearchBinding binding;
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2};
private final String key;
private BusStopInterface busStopInterface;
private PlaceholderFragment fragment;
private SectionsPagerAdapter sectionsPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySearchBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
sectionsPagerAdapter = new SectionsPagerAdapter(SearchActivity.this);
ViewPager2 pager = binding.viewPager;
pager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = binding.tabs;
EditText searchBox = binding.searchBox;
fragment = new PlaceholderFragment();
new TabLayoutMediator(tabs, pager, (tab, position) -> tab.setText(TAB_TITLES[position])).attach();
RetrofitClient retrofitClient = RetrofitClient.getInstance();
busStopInterface = RetrofitClient.getRetrofitInterface();
searchBox.addTextChangedListener(textWatcher);
pager.registerOnPageChangeCallback(pageChangeCallback);
}
ViewPager2.OnPageChangeCallback pageChangeCallback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
if (position == 0) {
Log.d("position", "Bus stop");;
} else if (position == 1) {
Log.d("position", "Bus");;
}
}
};
TextWatcher textWatcher = 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) {
}
@Override
public void afterTextChanged(Editable s) {
busStopInterface.getBusStop(key, 25, "json", 25, s.toString()).enqueue(new Callback<Example>() {
@Override
public void onResponse(Call<Example> call, Response<Example> response) {
if (response.isSuccessful()) {
Example example = response.body();
Items items = example.getResult().getBody().getItems(); //I checked the data response.
fragment.resetRecyclerView(items.getItem());
sectionsPagerAdapter.notifyDataSetChanged();
Log.d("retrofit", "Data fetch success");
} else {
Log.d("retrofit", "Data fetch fail");
}
}
@Override
public void onFailure(Call<Example> call, Throwable t) {
Log.d("retrofit", t.getMessage());
}
});
}
};
}
PlaceholderFragment
public class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
private PageViewModel pageViewModel;
private FragmentSearchBinding binding;
public List<BusStopItem> items = new ArrayList<>();
public SearchRecyclerViewAdapter adapter = new SearchRecyclerViewAdapter(items);
public static PlaceholderFragment newInstance(int index) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle bundle = new Bundle();
bundle.putInt(ARG_SECTION_NUMBER, index);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pageViewModel = new ViewModelProvider(this).get(PageViewModel.class);
int index = 1;
if (getArguments() != null) {
index = getArguments().getInt(ARG_SECTION_NUMBER);
}
pageViewModel.setIndex(index);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
binding = FragmentSearchBinding.inflate(inflater, container, false);
View root = binding.getRoot();
pageViewModel.getIndex().observe(getViewLifecycleOwner(), new Observer<Integer>() {
@Override
public void onChanged(Integer index) {
if (index == 1) {
adapter.setItemViewType(SearchRecyclerViewAdapter.VIEWTYPE_BUS_STOP);
} else if (index == 2) {
adapter.setItemViewType(SearchRecyclerViewAdapter.VIEWTYPE_BUS);
}
}
});
return root;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
RecyclerView recyclerView = binding.searchRecyclerView;
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), 1));
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
public void resetRecyclerView(List<BusStopItem> newItems) {
items.clear();
items.addAll(newItems);
adapter.notifyDataSetChanged();
}
}
SearchRecyclerViewAdapter
public class SearchRecyclerViewAdapter extends RecyclerView.Adapter<SearchRecyclerViewAdapter.ViewHolder> {
public static final int VIEWTYPE_BUS_STOP = 0;
public static final int VIEWTYPE_BUS = 1;
int mItemViewType;
List<BusStopItem> busStopItems;
public class ViewHolder extends RecyclerView.ViewHolder {
TextView busStopName, busStopId, busStopLocation, busName, busArea, busRoute;
public ViewHolder(@NonNull View itemView) {
super(itemView);
busStopName = itemView.findViewById(R.id.busStopName);
busStopId = itemView.findViewById(R.id.busStopId);
busStopLocation = itemView.findViewById(R.id.busStopLocation);
busName = itemView.findViewById(R.id.busName);
busArea = itemView.findViewById(R.id.busArea);
busRoute = itemView.findViewById(R.id.busRoute);
}
public void setBusStopItem(BusStopItem item) {
busStopName.setText(item.getNodenm());
if(item.getNodeno() != null) {
busStopId.setText(item.getNodeno().toString());
}
}
}
public SearchRecyclerViewAdapter(List<BusStopItem> busStopItems) {
this.busStopItems = busStopItems;
}
public void setItemViewType(int viewType) {
mItemViewType = viewType;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = null;
if (viewType == VIEWTYPE_BUS_STOP) {
view = inflater.inflate(R.layout.search_bus_stop_item, parent, false);
} else if (viewType == VIEWTYPE_BUS) {
view = inflater.inflate(R.layout.search_bus_item, parent, false);
}
SearchRecyclerViewAdapter.ViewHolder vh = new SearchRecyclerViewAdapter.ViewHolder(view);
return vh;
}
@Override
public int getItemViewType(int position) {
return mItemViewType;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
if (mItemViewType == VIEWTYPE_BUS_STOP) {
holder.setBusStopItem(busStopItems.get(position));
} else if (mItemViewType == VIEWTYPE_BUS) {
}
}
@Override
public int getItemCount() {
return busStopItems.size();
}
}
SectionsPagerAdapter
public class SectionsPagerAdapter extends FragmentStateAdapter {
public SectionsPagerAdapter(FragmentActivity fa) {
super(fa);
}
@NonNull
@Override
public Fragment createFragment(int position) {
return PlaceholderFragment.newInstance(position + 1);
}
@Override
public int getItemCount() {
return 2;
}
}
What I tried
public void resetRecyclerView(List<BusStopItem> newItems) {
items.clear();
items.addAll(newItems);
adapter.notifyDataSetChanged();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(this).attach(this).commit();
}
java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.fragment.app.FragmentTransaction androidx.fragment.app.FragmentManager.beginTransaction()' on a null object reference
You create PlaceholderFragment
but not add it to FragmmentManger
.
fragment = new PlaceholderFragment();
private PlaceholderFragment fragment
and fragment is not attach to any Activity,so UI dosen't refresh.
You should get PlaceholderFragment
instance from SectionsPagerAdapter
or create PlaceholderFragment
instance for SectionsPagerAdapter
, and you can set data to real PlaceholderFragment
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySearchBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
fragments = new ArrayList<>();
fragments.add(PlaceholderFragment.newInstance(1));
fragments.add(PlaceholderFragment.newInstance(2));
sectionsPagerAdapter = new SectionsPagerAdapter(SearchActivity.this, fragments);
ViewPager2 pager = binding.viewPager;
pager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = binding.tabs;
EditText searchBox = binding.searchBox;
new TabLayoutMediator(tabs, pager, (tab, position) -> tab.setText(TAB_TITLES[position])).attach();
RetrofitClient retrofitClient = RetrofitClient.getInstance();
busStopInterface = RetrofitClient.getRetrofitInterface();
searchBox.addTextChangedListener(textWatcher);
pager.registerOnPageChangeCallback(pageChangeCallback);
}
public class SectionsPagerAdapter extends FragmentStateAdapter {
private final List<PlaceholderFragment> fragments;
public SectionsPagerAdapter(FragmentActivity fa, List<PlaceholderFragment> fragments) {
super(fa);
this.fragments = fragments;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return 2;
}
}
busStopInterface.getBusStop(key, 25, "json", 25, s.toString()).enqueue(new Callback<Example>() {
@Override
public void onResponse(Call<Example> call, Response<Example> response) {
if (response.isSuccessful()) {
Example example = response.body();
Items items = example.getResult().getBody().getItems(); //I checked the data response.
fragments.get(1).resetRecyclerView(items.getItem());
Log.d("retrofit", "Data fetch success");
} else {
Log.d("retrofit", "Data fetch fail");
}
}
@Override
public void onFailure(Call<Example> call, Throwable t) {
Log.d("retrofit", t.getMessage());
}
});
PS. remove
FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.detach(this).attach(this).commit();