Android - set adapter inside retrofit - android

In a Fragment, in the onCreateView method, I set the adapter in this way:
final BusStopAdapter mAdapter = new BusStopAdapter(nearbyBusStations);
mRecyclerView.setAdapter(mAdapter);
Then there is a retrofit method which set the nearbyBusStations in the adapter:
service.getJson(origin, dest).enqueue(new Callback<DirectionResults>() {
#Override
public void onResponse(Call<DirectionResults> call, Response<DirectionResults> response) {
Route routeA = response.body().getRoutes().get(0);
Legs legs = routeA.getLegses().get(0);
nearbyBusStations.add(new NearbyBusStation(currentItem.getName(), String.valueOf(legs.getDistance().getValue()), legs.getDuration().getText()));
mAdapter.swapItems(nearbyBusStations);
mAdapter.notifyItemInserted(nearbyBusStations.size() - 1);
}
#Override
public void onFailure(Call<DirectionResults> call, Throwable t) {
Log.d("CallBack", " Throwable is " + t);
}
});
These lines of code works, but the problem is that I want to clear the mRecyclerView in another AsyncTask. I've tried some ways but nothing works.
I need to clear the mRecyclerView because I have to refresh the near bus stop station.

Simply clear your arraylist and notify your adapter where you want to clear your recyclerview.
Example:-
nearbyBusStations.clear();
mAdapter.setnotifyDataSetChanged();
Hope its help you..

You should clear your list and notify the adapter as below
nearbyBusStations.clear();
mAdapter.setnotifyDataSetChanged();

Related

RecyclerViewAdapter not updating after an observable change

So I a fragment, which observes a list on a viewmodel, below is the code for that:
homeViewModel.getUrgentCharityList()
.observe(getViewLifecycleOwner(), new Observer<List<Charity>>() {
#Override
public void onChanged(List<Charity> charities) {
urgentCharityListRecyclerView.getAdapter().notifyDataSetChanged();
Log.d(TAG, String.format("Urgent charity list changed. %d items in list",
urgentCharityListRecyclerView.getAdapter().getItemCount()));
}
});
On observed change on the list, I just notify the RecyclerViewAdapter to refresh the RecyclerView.
Here is the code when I initialized the RecyclerView:
public void initializeCharityRecyclerView() {
// Urgent charity list
urgentCharityListRecyclerView = rootView.findViewById(R.id.rv_home_urgentCharityList);
LinearLayoutManager urgentLayoutManager = new LinearLayoutManager(requireContext(),
LinearLayoutManager.HORIZONTAL, false);
urgentCharityListRecyclerView.setLayoutManager(urgentLayoutManager);
urgentCharityListRecyclerView.setAdapter(new CharityRecyclerViewAdapter(requireContext(),
homeViewModel.getUrgentCharityList().getValue()));
}
The problem is that when the fragment is first created, the list data is fetched, but the RecyclerView doesn't refresh, weirdly when I change to another fragment then comes back the RecyclerView updates.
Below is my code for fetching the data from Firestore:
public void updateUrgentCharityList() {
isUpdating.setValue(Boolean.TRUE);
// Query all charities from Firestore
charityRepository.getCurrentCharity().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()) {
List<Charity> newUrgentCharityList = new ArrayList<Charity>();
// Loop through query result
for(QueryDocumentSnapshot document: task.getResult()) {
// Convert query result into Charity object
Charity charity = document.toObject(Charity.class);
// Add Charity object into charityList
newUrgentCharityList.add(charity);
Log.d("HomeFragment", "Charity list query successful");
}
urgentCharityList.setValue(newUrgentCharityList);
}
else {
Log.e(TAG, "Charity list query failed");
}
isUpdating.setValue(Boolean.FALSE);
}
});
}
I tried not notifying the adapter, but replacing the adapter with a new adapter it seems to work, but I think it's not a good way to replace the adapter for every change in the list.
The only problem that I could think of is because the data fetching is async, then that becomes a syncing issue? But why did replacing the adapter work then?
Can anybody explain the actual problem here?
Declare the adapter in class level
CharityRecyclerViewAdapter charityAdapter;
public void initializeCharityRecyclerView() {
// Urgent charity list
urgentCharityListRecyclerView = rootView.findViewById(R.id.rv_home_urgentCharityList);
LinearLayoutManager urgentLayoutManager = new LinearLayoutManager(requireContext(),
LinearLayoutManager.HORIZONTAL, false);
urgentCharityListRecyclerView.setLayoutManager(urgentLayoutManager);
charityAdapter=new CharityRecyclerViewAdapter(requireContext(),homeViewModel.getUrgentCharityList().getValue());
urgentCharityListRecyclerView.setAdapter(charityAdapter);
}
then change the list visibility from private to public in your adapter class and update the list in the observer before calling notifyDatasetChanged
homeViewModel.getUrgentCharityList()
.observe(getViewLifecycleOwner(), new Observer<List<Charity>>() {
#Override
public void onChanged(List<Charity> charities) {
charityAdapter.charities=charities;
charityAdapter.notifyDataSetChanged();
Log.d(TAG, String.format("Urgent charity list changed. %d items in list",
urgentCharityListRecyclerView.getAdapter().getItemCount()));
}
});

call.enqueue not working for two retrofit calls in same class

Hello I am new to Android. I am trying to call and save two API from same class and place both data from those API into same RecyclerView.
The first retrofit is working but in the second retrofit call there is problem.
The code is as below for second retrofit
private void callRetrofitListData(){
pariyojanaInterfaces = ApiClient.getApiClient().create(PariyojanaInterface.class);
Log.e("pariyojanaInterfaces", String.valueOf(pariyojanaInterfaces));
Call<List<Data>> call = pariyojanaInterfaces.getData(memberId);
Log.e("urll",call.request().toString())
call.enqueue(new Callback<List<Data>>() {
#Override
public void onResponse(Call<List<Data>> call, Response<List<Data>> response) {
Log.e("check","chekc");
datas = (List<Data>) response.body();
itemListAdapter = new ItemListAdapter(getApplicationContext(), datas);
rv.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
rv.setAdapter(itemListAdapter);
}
#Override
public void onFailure(Call<List<Data>> call, Throwable t) {
Log.e("error", t.getMessage());
}
});
}
In this case the debugger is not going inside this function
call.enqueue(new Callback<List<Data>>()
and says No such instance field: 'PariyojanaInterfaces'.
The PariyojanaInterface is shown below:
public interface PariyojanaInterface {
#POST("projectBudget/pariyojanaListForMobile")
Call<List<Data>> getData(#Query("memberId") int memberId);
}
Can somebody please help me solve my problem?
You have to add #FormUrlEncoded in your interface before #POST() line
and
in POST method we use #FIELD instead of #QUERY

Add query parameter to Retrofit get in Android Studio

I'm trying to use retrofit for get records from my API and it works fine when i do something like this.
public interface materialAPI {
#GET("/mlearningServices/Course")
public void getMaterials(Callback<List<materialClass>> response); } public void getMaterials()
{
RestAdapter adapter = new RestAdapter.Builder().setEndpoint(Root_Url).build();
Log.i(TAG , "hERE IS THE LINK"+adapter.toString());
materialAPI api = adapter.create(materialAPI.class);
api.getMaterials(new Callback <List<materialClass>>() {
#Override
public void success(List<materialClass> list, Response response) {
materials = list;
showList();
customAdapter customAdapter = new customAdapter();
listView.setAdapter(customAdapter);
}
#Override
public void failure(RetrofitError error) {
}
});
}
The above code works fine and i can get all my materials but what i want to achieve next is get material with any id . When a user selects a paticular material, i want to pass the id into the get url so i can get the records
meaning i have to do something like this
#GET("/mlearningServices/Course/{myId}")
..
How to i add myId to the callback method. This is my first time of using retrofit
Use the #Path annotation
#POST("/mlearningServices/Course/{myId}")
public void getMaterials(#Path("myId") String id, Callback<Response> response);
References:
https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/Path.html
http://square.github.io/retrofit/
That you are asking about is called a path variable. To set one, you must rewrite your method signature as this:
public void getMaterials(#Path("myId") String id, Callback<List<materialClass>> response);
This way, the variable defined as /path/to/your/endpoint/{nameOfPathVariable} will be injected into that String parameter passed to the method. You could also define it as an Integer, and retrofit will try to cast it accordingly.
Solution:
You can use this to pass your id, Use the #Path annotation
#GET("/mlearningServices/Course/{myId}")
Call<materialClass> getMaterials(#Path("myId") String id);
#Path is some data that you wish to provide it to GET method before Question Mark ("?") and #Query("..") is some data you wish to provide after "?"
Hope you have understood.

Why does ArrayAdapter fail to update listview after activity restart?

I have an activity that in onCreate() does the following:
Creates an empty ArrayList
Creates a new ArrayAdapter associated with the above ArrayList
Sets ListView to use the above ArrayAdapter
Uses Volley to send a GET request to my API to fetch some JSON data to load into the ListView
Once the data is fetched I add it to my ArrayList and the ListView is populated as expected
My problem is that when the activity is restarted (i.e. the screen is rotated via the emulator or the activity is restarted through Android Studio) the ListView no longer populates.
I am not saving any state. I expect the activity to return to its initial default state so I don't think onSaveInstanceState() is the answer.
I've verified that the data is returned successfully from the API and that the adapter's hashcode is the same before and after the volley request and that it equals the ListView's set adapter. I've also verified that onDestroy() and then onCreate() are called when the activity is restarted so I know it is going through a full life cycle.
If I rotate the screen programmatically with setRequestedOrientation() I don't experience this issue. If I add items to my ArrayList outside of the GET request callback, I don't experience this issue.
Here is my activity onCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//The data to be displayed
descriptions = new ArrayList<>();
listView = (ListView)this.findViewById(R.id.myListView);
//Link 'descriptions' to the adapter
adapter = new ArrayAdapter<>(this, R.layout.list_json_text_view, descriptions);
listView.setAdapter(adapter);
this.addTextFilter();
this.addListViewClickListener();
//See my ApiGetRequest class below
request = new ApiGetRequest();
request.send(this.getContext(), getDataUrl(), this, "", REQUEST_TYPES.TEXT);
}
And my activity GET request callback
public void onSuccess(DescriptiveJSONArray items, REQUEST_TYPES type) {
descriptions.clear();
try {
for (int i = 0; i < items.length(); ++i) {
JSONObject obj = items.getJSONObject(i);
String desc = obj.optString("name", "") + " " + obj.optString("description", "");
//TODO: Remove debug code
System.out.println("Adding: "+desc);
descriptions.add(desc);
}
}
catch(JSONException e) {
e.printStackTrace();
//getJSONObject failed
}
}
And my ApiGetRequest methods
//My activity implements ApiGetCallback
public void send(Context context, String url, ApiGetCallback callback, String tag, REQUEST_TYPES type) {
StringRequest stringRequest = getStringRequest(url, callback, tag, type);
//Singleton wrapper for RequestQueue
AppRequestQueue queue = AppRequestQueue.getInstance(context);
queue.add(stringRequest);
}
//Inner class inside ApiGetCallback
class SuccessListener implements Response.Listener<String> {
ApiGetCallback callback;
REQUEST_TYPES type;
public SuccessListener(ApiGetCallback callback, REQUEST_TYPES type) {
this.callback = callback;
this.type = type;
}
#Override
public void onResponse(String response) {
try {
DescriptiveJSONArray jsonResp = new DescriptiveJSONArray(response);
callback.onSuccess(jsonResp, type);
}
catch(JSONException e) {
callback.onJsonException(e);
}
}
}
Any ideas what is happening?. I'm testing on Marshmallow and Nougat
You are missing a call to notifyDataSetChanged, after the onSuccess function is done.
you may need to override onStart and do update anything in it
adapter = new ArrayAdapter<>(this, R.layout.list_json_text_view, descriptions);
listView.setAdapter(adapter);
//See my ApiGetRequest class below
request = new ApiGetRequest();
request.send(this.getContext(), getDataUrl(), this, "", REQUEST_TYPES.TEXT);
use this part of code in onResume method.

Null pointer in retrofit callback when call getActivity

I'm using retrofit for fetching data from resource. But think my architecture is wrong.
So, i have an fragment with listview, for example.
In onCreateView after UI setup i calls API method(async). That returns list of models i need to setup my listview adapter.
Thats i do in callback
private Callback<List<User>> mUsersCallback = new Callback<List<User>>() {
#Override
public void success(List<User> users, Response response) {
mLoadingLayout.hideLoading();
mPeopleAdapter = new PeopleAdapter(getActivity(), users);
lvPeople.setAdapter(mPeopleAdapter);
}
#Override
public void failure(RetrofitError error) {
mLoadingLayout.hideLoading();
Log.d("get users", error.getUrl() + " " + error.toString());
}
};
In this part i sometimes get NPE when call getActivity();
How to do it on right way?
Your activity has been destroyed during the call, when you try to get it in your callback, it may be null.
Simply check if activity is not null and if null ignore the callback.
Try to create your own Callback class and there pass your Activity or Context by constructor.
Similar to this answer: https://stackoverflow.com/a/25665521/2399340

Categories

Resources