Swipe to refresh data using SwipeRefreshLayout in fragment? - java

I want my layout to be refreshed when the app starts and the data should show in and when the user swipes the data should be updated and show new data if new data is available on the server.
The actual problem is that the data is not loading when the app is started. Rather it is happening only on swiping. How can I achieve that on opening the app the data is loaded first and then the data is updated on swiping?
public class FirstFragment extends Fragment {
FragmentFirstBinding binding;
APIInterfaces interfaces;
ArrayList<VideoModels> list = new ArrayList<>();
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentFirstBinding.inflate(inflater, container, false);
MyAdapter adapter = new MyAdapter(list,getContext());
binding.myRecyclerView.setAdapter(adapter);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(),2);
binding.myRecyclerView.setLayoutManager(gridLayoutManager);
interfaces = RetrofitInstance.getRetrofit().create(APIInterfaces.class);
binding.swipeToRefresh.setRefreshing(true);
binding.swipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
interfaces.getPosts().enqueue(new Callback<List<VideoModels>>() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onResponse(#NonNull Call<List<VideoModels>> call, #NonNull Response<List<VideoModels>> response) {
list.clear();
if (response.isSuccessful()) {
assert response.body() != null;
list.addAll(response.body());
adapter.notifyDataSetChanged();
binding.swipeToRefresh.setRefreshing(false);
}
}
#Override
public void onFailure(#NonNull Call<List<VideoModels>> call, #NonNull Throwable t) {
Toast.makeText(getContext(), "Check you Internet", Toast.LENGTH_SHORT).show();
binding.swipeToRefresh.setRefreshing(false);
}
});
}
});
binding.swipeToRefresh.setRefreshing(false);
return binding.getRoot();
}
}
EDIT-1: Added complete code.
Your answer will helpful for me.

You need to call this method in onResume() state
public void getData() {
interfaces.getPosts().enqueue(new Callback<List<VideoModels>>() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onResponse(#NonNull Call<List<VideoModels>> call, #NonNull Response<List<VideoModels>> response) {
list.clear();
if (response.isSuccessful()) {
assert response.body() != null;
list.addAll(response.body());
adapter.notifyDataSetChanged();
binding.swipeToRefresh.setRefreshing(false);
}
}
#Override
public void onFailure(#NonNull Call<List<VideoModels>> call, #NonNull Throwable t) {
Toast.makeText(getContext(), "Check you Internet", Toast.LENGTH_SHORT).show();
binding.swipeToRefresh.setRefreshing(false);
}
});
}

if you call binding.swipeLayout.isRefreshing = true
in SwipeRefreshLayout source code, mNotify boolean value is false
so cannot do anything in setOnRefreshListener
public void onAnimationEnd(Animation animation) {
if (mRefreshing) {
// Make sure the progress view is fully visible
mProgress.setAlpha(MAX_ALPHA);
mProgress.start();
if (mNotify) {
if (mListener != null) {
mListener.onRefresh();
}
}
mCurrentTargetOffsetTop = mCircleView.getTop();
} else {
reset();
}
}
this is why setOnRefreshListener not invoke
if you want manual invoke it do like this by reflect set mNotify boolean value is true
val swipeClass = SwipeRefreshLayout::class.java
val method = swipeClass.getDeclaredMethod("setRefreshing", Boolean::class.java, Boolean::class.java)
method.isAccessible = true
method.invoke(binding.swipeLayout, true, true)

After finding the solution for 1 day. Finally, I found my solution.
To use SwipeRefreshLayout work in Fragment and want to refresh your data Onswipe. use the below code and modify it as your requirement.
This is a fragment.
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentFirstBinding.inflate(inflater, container, false);
// swiping on starting of an app.
binding.swipeToRefresh.setRefreshing(true);
getData();
binding.swipeToRefresh.setRefreshing(false);
// when user swipe
binding.swipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onRefresh() {
getData();
}
});
return binding.getRoot();
}
public void getData(){
// you have to put all of your onCreate code here to work properly. most of time it throws an error. So, make sure you added code properly.
ArrayList<VideoModels> list = new ArrayList<>();
MyAdapter adapter = new MyAdapter(list,getContext());
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(),2);
binding.myRecyclerView.setAdapter(adapter);
binding.myRecyclerView.setLayoutManager(gridLayoutManager);
binding.swipeToRefresh.setRefreshing(true);
interfaces = RetrofitInstance.getRetrofit().create(APIInterfaces.class);
interfaces.getPosts().enqueue(new Callback<List<VideoModels>>() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onResponse(#NonNull Call<List<VideoModels>> call, #NonNull Response<List<VideoModels>> response) {
list.clear();
if (response.isSuccessful()) {
assert response.body() != null;
list.addAll(response.body());
adapter.notifyDataSetChanged();
binding.swipeToRefresh.setRefreshing(false);
}
}
#Override
public void onFailure(#NonNull Call<List<VideoModels>> call, #NonNull Throwable t) {
Toast.makeText(getContext(), "Check you Internet", Toast.LENGTH_SHORT).show();
binding.swipeToRefresh.setRefreshing(false);
}
});
}

Related

What is the function that can be used instead of "this" in "Fragment"?

I'm implementing the autocomplete suggestion code in Google map place api.
We are using OnMapReadyCallback as an implement.
The MapView.getMapAsync(this) function was originally used in onCreateView. But now I'm going to use it in setupAutoCompleteFragment. However, in MapView.getMapAsync(this), it is not compiled due to this. What can be used?
public class googlemaptab extends Fragment implements OnMapReadyCallback {
MapView mapview;
Button kakaobutton;
public static googlemaptab newInstance(){
return new googlemaptab();
}
public googlemaptab() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_googlemaptab, container, false);
kakaobutton = (Button)view.findViewById(R.id.kakaobutton);
mapview = (MapView)view.findViewById(R.id.google_map_view);
setupAutoCompleteFragment();
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
kakaobutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//클릭하면 카카오maptab으로 이동하겠다.
((MainActivity)getActivity()).replaceFragment(kakaomaptab.newInstance());
}
});
}
#Override
public void onStart() {
super.onStart();
mapview.onStart();
}
#Override
public void onResume() {
super.onResume();
mapview.onResume();
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(mapview != null)
{
mapview.onCreate(savedInstanceState);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
LatLng SEOUL = new LatLng(37.56, 126.97);
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(SEOUL);
markerOptions.title("서울");
markerOptions.snippet("수도");
googleMap.addMarker(markerOptions);
googleMap.moveCamera(CameraUpdateFactory.newLatLng(SEOUL));
googleMap.animateCamera(CameraUpdateFactory.zoomTo(13));
}
private void setupAutoCompleteFragment() {
PlaceAutocompleteFragment autocompleteFragment = (PlaceAutocompleteFragment)getActivity().
getFragmentManager().findFragmentById(R.id.place_autocomplete_fragment);
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
mapview.getMapAsync(this);
}
#Override
public void onError(Status status) {
Log.e("Error", status.getStatusMessage());
}
});
}
}
You could do it better this way
private void setupAutoCompleteFragment(OnMapReadyCallback instance) {
PlaceAutocompleteFragment autocompleteFragment = (PlaceAutocompleteFragment)getActivity().
getFragmentManager().findFragmentById(R.id.place_autocomplete_fragment);
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
mapview.getMapAsync(instance);
}
#Override
public void onError(Status status) {
Log.e("Error", status.getStatusMessage());
}
});
}
And don't forget to update your onCreateView with the new function signature as the following:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_googlemaptab, container, false);
kakaobutton = (Button)view.findViewById(R.id.kakaobutton);
mapview = (MapView)view.findViewById(R.id.google_map_view);
setupAutoCompleteFragment(this);
return view;
}
You can use Classname.this in this case.
For example: if your fragment name is HomeFragment then,
HomeFragment.this
If this still doesn't work then you can override onViewCreated() function and call mapView.getMapAsync(this) inside onViewCreated()
If needed check this link
have you tried with mapview.getMapAsync(getActivity()); instead of mapview.getMapAsync(this);

How to display contents retrieved from Firebase Realtime Database on a ListView as the apps loads

I'm trying to display records saved in Firebase Database to the user in a ListView as The Application loads but it's not working.
The problem is that when the app loads for the first time the contents are not added to the ListView.
As I'm testing the app I noticed that the contents are not displayed as I open the app for the first time but only if I close the app by pressing the back button and then reopen it.
I add this method: adapter.notifyDataSetChanged(); to the onStart() as suggested by some guy but it didn't work.
This is the method that fetches the data:
private void fetchData() {
if (FirebaseDatabase.getInstance() != null) {
FirebaseDatabase.getInstance().goOffline();
}
FirebaseDatabase.getInstance().goOnline();
Query query = FirebaseDatabase.getInstance().getReference().child("User");
FirebaseRecyclerOptions<User> options =
new FirebaseRecyclerOptions.Builder<User>()
.setQuery(query, new SnapshotParser<User>() {
#NonNull
#Override
public User parseSnapshot(#NonNull DataSnapshot snapshot) {
s = snapshot.getChildrenCount();
Toast.makeText(getApplicationContext(), Long.toString(s), Toast.LENGTH_SHORT).show();
return new User(snapshot.child("fullName").getValue().toString(),
snapshot.child("userId").getValue().toString());
}
})
.build();
adapter = new FirebaseRecyclerAdapter<User, MyViewHolder>(options) {
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.database_contents, parent, false);
return new MyViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull MyViewHolder myViewHolder, final int i,
#NonNull User user) {
myViewHolder.setTxtFullName(user.getFullName());
myViewHolder.setTxtUserId(user.getUserId());
myViewHolder.root.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), String.valueOf(i), Toast.LENGTH_SHORT).show();
}
});
}
};
}
and this is where I made the call:
#Override
protected void onStart() {
super.onStart();
fetchData();
recyclerView.setAdapter(adapter);
adapter.startListening();
adapter.notifyDataSetChanged();
}
I also tried calling the fetchData() method in onCreate.
I will like the contents to be displayed in the ListView as the App loads for the first time. Thanks in advance
here is simple way to get firebase data in listview as below..
final DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference().child("Contacts");
mDatabase.child(user_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshott) {
list = new ArrayList<>();
for (DataSnapshot ds : dataSnapshott.getChildren()){
final String key_idd = ds.getKey();
Listdata listdata = new Listdata();
String name=ds.child("name").getValue(String.class);
listdata.setName(name);
listdata.setKey_id(key_idd);
list.add(listdata);
}
recycler = new RecyclerviewAdapter(MyContactActivity.this, list);
recyclerview.setAdapter(recycler);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e("Error", "Failed to read user", error.toException());
}
});
Firebase uses listener for reading data so you see your result on your second opening. You should use interface for data reading.

How to use EventBus in fragment?

In my application i use fragment into Activity and i want when run one code into fragment, call some codes in Activity.
I write below codes but when load data not run activity code.!
Fragment codes:
public void loadRecentPosts() {
ApiUtils.getApiInterface().getRecentPosts(AppConstant.DEFAULT_PAGE).enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if (response.isSuccessful()) {
if (!recentPostList.isEmpty()) {
recentPostList.clear();
}
recentPostList.addAll(response.body());
if (recentPostList.size() > 0) {
recentPostAdapter.notifyDataSetChanged();
EventBus.getDefault().post(new LoadMainDataEvent());
}
} else {
showEmptyView();
}
pbSectionLoader.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
showEmptyView();
t.printStackTrace();
}
});
}
}
Activity code:
#Subscribe (threadMode = ThreadMode.MAIN)
public void onLoadMainDataEvent(LoadMainDataEvent loadMainDataEvent){
Toast.makeText(activity, "OK", Toast.LENGTH_SHORT).show();
}
I want when get data from server into fragment, run codes in activity page.
How can i fix it? please help me. Thanks
Try this it work fine
FragmentClass.java
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageBusEvent event) {
}
#Override
public void onDestroy() {
//unregister event bus
EventBus.getDefault().unregister(this);
super.onDestroy();
}

ClassCastException error when using setOnScrollListener

Below is a code where data will come at scrolling time but there is an error i.e
ClassCastException. Please help me to solve this error. Now I have added my whole fragment class Similar_Matchs_Tab where we fetching the from server.
java.lang.ClassCastException: com.devbhoomimedia.maangal.ProfilesActivity cannot be cast to android.widget.AbsListView$OnScrollListener
public class Similar_Matchs_Tab extends Fragment {
private ListView listView;
public Similar_Matchs_Tab() {}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
JSON_URL = "https://www.maangal.com/maangal_mobile/similar_matches.php?matri_id="+email;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Inflate the layout for this fragment
View view= inflater.inflate(R.layout.matches_tab, container, false);
listView = (ListView) view.findViewById(R.id.listView);
listView.setOnScrollListener((AbsListView.OnScrollListener) getActivity());
sendRequest();
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
});
return view;
}
sendRequest function to fetch the data
private void sendRequest(){
final ProgressDialog loading = ProgressDialog.show(getActivity(),"Loading Data", "Please wait...",false,false);
StringRequest stringRequest = new StringRequest(Request.Method.POST,JSON_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
loading.dismiss();
showJSON(response);
Log.e("Similar MAtches******",response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(),error.getMessage(), Toast.LENGTH_LONG).show();
}
});
int MY_SOCKET_TIMEOUT_MS = 30000;
stringRequest.setRetryPolicy(new DefaultRetryPolicy(
MY_SOCKET_TIMEOUT_MS, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
requestQueue.add(stringRequest);
}
protected void showJSON(String json){
ParseJSON pj = new ParseJSON(json);
pj.parseJSON();
Profile_Match_custom_List cl = new Profile_Match_custom_List(getActivity(), ParseJSON.ids,ParseJSON.ages, ParseJSON.heights, ParseJSON.communities,ParseJSON.castes,ParseJSON.educations,ParseJSON.occupations,ParseJSON.incomes,ParseJSON.pics,ParseJSON.locations,ParseJSON.shortlist,ParseJSON.expressinterest);
listView.setAdapter(cl);
}
}
B'coz you're casting Activity into AbsListView.OnScrollListener interface that's why you're getting classCastException.
just remove listView.setOnScrollListener((AbsListView.OnScrollListener) getActivity());
and replace
listView.setOnScrollListener((ProfileActivity) getActivity());
The reason why you're getting this error is because you're trying to cast activity to a scroll listener which is not possible. So to fix the problem just set the appropriate interface and it should work. Replace listView.setOnScrollListener((AbsListView.OnScrollListener) getActivity()); with this:
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
});
change it
listView.setOnScrollListener((AbsListView.OnScrollListener) getActivity());
to
listView.setOnScrollListener((ProfileActivity)getActivity());
and ProfileActivity must implements AbsListView.OnScrollListener.
Your activity does not implement AbsListView.OnScrollListener interface.

Destroyed fragment content remains on screen

I have fragments making API call via Retrofit + RxJava. I subscribe the Subscription in onActivityCreated and dispose at onDestroy. When I switch from FragmentA to FragmentB while FragmentA is still processing the API call, FragmentB appears below the content of FragmentA. It means FragmentA contents remains on top of the screen and there is no control over it.
FragmentA.java
public class FragmentA extends Fragment {
#BindView(R.id.swipe_refresh) SwipeRefreshLayout mSwipeRefresh;
#BindView(R.id.recycler_view) RecyclerView mRecyclerView;
private ItemsAdapter mAdapter;
private CompositeDisposable mCompositeDisposable = new CompositeDisposable();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_list, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
ButterKnife.bind(this, view);
mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
fetchItems();
}
});
mAdapter = new ItemsAdapter();
mRecyclerView.setAdapter(mAdapter);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSwipeRefresh.setRefreshing(true);
fetchItems();
}
#Override
public void onDestroy() {
super.onDestroy();
mCompositeDisposable.clear();
}
private void fetchItems() {
RequestInterface requestInterface = Utils.createService();
mCompositeDisposable.add(requestInterface.getItemsForA()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Response>() {
#Override
public void accept(#NonNull Response response) throws Exception {
mAdapter.swapItems(response.getItems());
mSwipeRefresh.setRefreshing(false);
}
}, new Consumer<Throwable>() {
#Override
public void accept(#NonNull Throwable throwable) throws Exception {
Toast.makeText(getActivity(), "Error: " + throwable.getLocalizedMessage(), Toast.LENGTH_LONG).show();
mSwipeRefresh.setRefreshing(false);
}
}));
}
}
FragmentB.java
public class FragmentB extends Fragment {
//Same as `FragmentA` but different API call
}
I have also did some logging and found out that all of the life-cycle methods for FragmentA including onDestroyView gets called.
You need to call following methods on SwipeRefreshLayout to fix this.
swipeRefreshLayout.setRefreshing(false);
swipeRefreshLayout.destroyDrawingCache();
swipeRefreshLayout.clearAnimation();
super.onDestroyView();
}

Categories