How to reload Volley data to get current items from json - android

I have this recyclerview that loads data from a server through a json api. the Data on the server will be updated frequently so i have a "swipe to refresh" in my application. I'm using volley to get the data from the server and i want to make it in such a way that, when the user swipe to refresh, volley will reload the json data from the server so that recyclerview can display the newly added items.
This is my onSwipeListener
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
}
}, 3000);
}
});
This is how volley is requesting the data
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
public ArrayList<Deal> userlist;
public DealAdapter adapter;
#Override
public void onResponse(String response) {
MainActivity.userList = this.userlist;
userList = new JsonConverter<Deal>().
toArrayList(response, Deal.class);
Collections.reverse(userList);
adapter = new DealAdapter(getApplicationContext(), userList);
MainActivity.adapter= this.adapter;
recyclerView.setAdapter(adapter);
}
But i can't figure out how to refresh the volley response data when onSwipeListener is called.
this is how i add the request to Queue
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);

I think the problem is that you are re-assigning the Activity adapter, but never setting that new adapter back onto the Activity's RecyclerView.
Sure, you have recyclerView.setAdapter(adapter), but it is not clear where that reference came from.
Similarly, the Activity's userList is empty.
MainActivity.userList = this.userlist; // This is null
userList = new JsonConverter<Deal>(). // This should have been first
toArrayList(response, Deal.class);
So, anyways, as I was saying in the comments, static variables are really not a good way to "toss data over the Java class wall".
Let's say you have this class to handle all the Volley calls. Notice that the Response.Listener interface is passed as the parameter.
public class JsonApi {
private Context mContext;
private static JsonApi instance;
private JsonApi(Context c) { this.mContext = c; }
public static JsonApi getInstance(Context context) {
if (instance == null) instance = new JsonApi(context);
return instance;
}
public void getSomeData(Response.Listener<String> success) {
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, success);
MySingleton.getInstance(this.mContext).addToRequestQueue(stringRequest);
}
}
Now, over in the Activity or Adapter, you can get this class and re-do Volley requests whenever.
(Apologies for any typos. This is untested, but it just gives a sample of how I would layout the code).
public class MainActivity implements
SwipeRefreshLayout.OnRefreshListener,
Response.Listener<String> {
private List<Deal> userList;
private DealAdapter adapter;
private RecyclerView recyclerView;
private SwipeRefreshLayout swipeRefreshLayout;
private JsonApi api;
#Override
public void onResponse(String response) {
userList.clear();
userList.addAll(new JsonConverter<Deal>().
toArrayList(response, Deal.class));
Collections.reverse(userList);
// Handle adapter updates here
if (swipeRefreshLayout.isRefreshing()) {
swipeRefreshLayout.setRefreshing(false);
}
recyclerView.notifyDataSetChanged();
}
#Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// Start an API call to refresh data
api.getSomeData(MainActivity.this);
}
}, 3000);
}
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.activity_main);
api = JsonApi.getInstance(MainActivity.this);
userList = new ArrayList<Deal>();
adapter = new DealAdapter(MainActivity.this, userList);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
// set layout manager ... etc.
recyclerView.setAdapter(adapter);
api.getSomeData(MainActivity.this); // start the first call when the activity starts
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefresh);
swipeRefreshLayout.setOnRefreshListener(MainActivity.this);
}
}

Okay So this is what worked for me. I had to call StringRequest again in the OnRefreshListener with new variable so that when the user swipes, volley requests the json data again and pass it to the adapter as shown below.
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
StringRequest mrequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
public ArrayList<Deal> userlist;
public DealAdapter adapter;
#Override
public void onResponse(String response) {
MainActivity.userList = this.userlist;
userList = new JsonConverter<Deal>().
toArrayList(response, Deal.class);
Collections.reverse(userList);
adapter = new DealAdapter(getApplicationContext(), userList);
MainActivity.adapter= this.adapter;
recyclerView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, error.toString());
Toast.makeText(getApplicationContext(), "Something Went wrong: " + "'" + error + "'", Toast.LENGTH_LONG).show();
}
});
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(mrequest);
adapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
}
}, 3000);
}
});

Related

data not showing in recyclerview using notifyDataSetChanged in Retrofit but works in volley

I always use the approach to show the data in recyclerview using Volley is to create Adapter in Oncreate method and then notify after receiving response from volley using notifyDataSetChanged.
I tried to use the same approach in Retrofit but data is not showing in Recyclerview,but if instead of setting adapter in Oncreate method if I set Adapter in retrofit after receiving response from Retrofit then it works perfectly
My question is that
(1) why the data is not showing in Retrofit if i create adapter in Oncreate am i doing something wrong?
(2)Is it a good approach to create adapter in Oncreate and then notifying it after receiving response or shoud I set adapter after getting response?
If I set adapter after getting response like this
#Override
public void onResponse(Call<SubCatModelList> call, Response<SubCatModelList> response) {
Log.d("subcategoryJsonResponse", String.valueOf(response));
Gson gson = new Gson();
String successResponse = gson.toJson(response.body());
Log.d("aaaaaa", String.valueOf(successResponse));
if (response.isSuccessful()) {
subCatModel =response.body().getSubCategories();
Log.d("asaaaaaaa", String.valueOf(subCatModel));
subCategoryAdapter = new SubCategoryAdapter(BinaryCommissionActivity.this, subCatModel);
FixedGridLayoutManager manager = new FixedGridLayoutManager();
manager.setTotalColumnCount(1);
rvBinaryCommission.setLayoutManager(manager);
rvBinaryCommission.setAdapter(subCategoryAdapter);
rvBinaryCommission.addItemDecoration(new DividerItemDecoration(BinaryCommissionActivity.this, DividerItemDecoration.VERTICAL));
}
then every time this line initializes adapter and creates object whenver api hits and i think its a bad approach
subCategoryAdapter = new
SubCategoryAdapter(BinaryCommissionActivity.this, subCatModel);
public class BinaryCommissionActivity extends AppCompatActivity {
int scrollX = 0;
List<SubCatModel> subCatModel = new ArrayList<>();
SubCategoryAdapter subCategoryAdapter;
VolleyCustomClass volleyCustomClass;
#BindView(R.id.toolbarcustom) Toolbar toolbarcustom;
#BindView(R.id.spinner_binary_commission) Spinner spinnerBinaryCommission;
#BindView(R.id.searchViewBinary) SearchView searchViewBinary;
#BindView(R.id.headerScroll) HorizontalScrollView headerScroll;
#BindView(R.id.rvBinaryCommission) RecyclerView rvBinaryCommission;
#BindView(R.id.swipeRefreshBinaryList) SwipeRefreshLayout swipeRefreshBinaryList;
private AlertDialog dialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_binary_commission);
ButterKnife.bind(this);
toolbarcustom = findViewById(R.id.toolbarcustom);
setSupportActionBar(toolbarcustom);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("Binary Commission");
volleyCustomClass = new VolleyCustomClass(getApplicationContext());
dialog = new SpotsDialog.Builder().setContext(this)
.setMessage("Loading...")
.setCancelable(false).build();
spinnerData();
setUpRecyclerView();
prepareClubData();
recyclerviewScrollListener();
searchFilter();
swipeRefreshBinaryList.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
if (!InternetUtils.checkForInternet(getApplicationContext())) {
swipeRefreshBinaryList.setRefreshing(false);
FancyToast.makeText(getApplicationContext(), "No Internet Connection", FancyToast.LENGTH_LONG, FancyToast.ERROR, false).show();
} else {
prepareClubData();
}
}
});
}
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return super.onSupportNavigateUp();
}
/**
* Recyclerview ScrollListener
*/
private void recyclerviewScrollListener() {
rvBinaryCommission.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
scrollX += dx;
headerScroll.scrollTo(scrollX, 0);
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
}
/**
* Search Filter
*/
private void searchFilter() {
searchViewBinary.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
subCategoryAdapter.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
subCategoryAdapter.getFilter().filter(newText);
return false;
}
});
}
/**
* Adding data to spinner
*/
private void spinnerData() {
List<String> show_entries = new ArrayList<String>();
show_entries.add("5");
show_entries.add("10");
show_entries.add("15");
show_entries.add("20");
show_entries.add("All");
ArrayAdapter<String> dataAdapterShowEntries = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, show_entries);
dataAdapterShowEntries.setDropDownViewResource(R.layout.layout_spinner_item);
spinnerBinaryCommission.setAdapter(dataAdapterShowEntries);
spinnerBinaryCommission.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
Object item = adapterView.getItemAtPosition(position);
if (item != null) {
// Toast.makeText(getContext(), item.toString(), Toast.LENGTH_SHORT).show();
}
// Toast.makeText(getContext(), "Selected", Toast.LENGTH_SHORT).show();
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
// TODO Auto-generated method stub
}
});
}
private void prepareClubData() {
if (!InternetUtils.checkForInternet(getApplicationContext())) {
FancyToast.makeText(getApplicationContext(), "No Internet Connection", FancyToast.LENGTH_LONG, FancyToast.ERROR, false).show();
return;
} else {
dialog.show();
if (subCatModel != null) {
subCatModel.clear();
}
/**
* Volley
*/
/* volleyCustomClass.callGetServer(URLs.subcategoryURL, new VolleyCallback() {
#Override
public void onSuccess(String response) {
Log.d("subcategoryJsonResponse", response);
try {
JSONObject obj = new JSONObject(response);
JSONArray productArray = obj.getJSONArray("sub-categories");
for (int i = 0; i < productArray.length(); i++) {
JSONObject productObject = productArray.getJSONObject(i);
SubCatModel subCatModelClass = new SubCatModel();
subCatModelClass.setSubcategoriesId(productObject.getString("Subcategories-Id"));
subCatModelClass.setCategoriesId(productObject.getString("categories-Id"));
subCatModelClass.setSubcategoriesName(productObject.getString("Subcategories-Name"));
subCatModel.add(subCatModelClass);
Log.d("subCategoryArraylist", String.valueOf(subCatModel));
}
dialog.dismiss();
subCategoryAdapter.notifyDataSetChanged();
swipeRefreshBinaryList.setRefreshing(false);
} catch (JSONException e) {
e.printStackTrace();
dialog.dismiss();
}
}
#Override
public void onError(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
swipeRefreshBinaryList.setRefreshing(false);
}
});*/
/**
* Retrofit
*/
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<SubCatModelList> call = apiService.getList();
call.enqueue(new Callback<SubCatModelList>() {
#Override
public void onResponse(Call<SubCatModelList> call, Response<SubCatModelList> response) {
Log.d("subcategoryJsonResponse", String.valueOf(response));
Gson gson = new Gson();
String successResponse = gson.toJson(response.body());
Log.d("aaaaaa", String.valueOf(successResponse));
if (response.isSuccessful()) {
subCatModel =response.body().getSubCategories();
Log.d("asaaaaaaa", String.valueOf(subCatModel));
}
dialog.dismiss();
subCategoryAdapter.notifyDataSetChanged();
swipeRefreshBinaryList.setRefreshing(false);
}
#Override
public void onFailure(Call<SubCatModelList> call, Throwable t) {
swipeRefreshBinaryList.setRefreshing(false);
}
});
}
}
/**
* Handles RecyclerView for the action
*/
private void setUpRecyclerView() {
subCategoryAdapter = new SubCategoryAdapter(BinaryCommissionActivity.this, subCatModel);
FixedGridLayoutManager manager = new FixedGridLayoutManager();
manager.setTotalColumnCount(1);
rvBinaryCommission.setLayoutManager(manager);
rvBinaryCommission.setAdapter(subCategoryAdapter);
rvBinaryCommission.addItemDecoration(new DividerItemDecoration(BinaryCommissionActivity.this, DividerItemDecoration.VERTICAL));
}
}
Instead of initializing adapter everytime, you can use: (inside adapter class)
public void setItems(List<String> myList) { // Let's say it's List of Strings
this.myList = myList;
notifyDataSetChanged();
}
And everytime you change List with your data to display (in your case inside of onResponse()) you just call 'setItems()' on your adapter.

Update RecyclerView items in android

I want to update the items inside RecyclerView using sending request to API and a timer.
This is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
get_items();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
synchronized public void run() {
get_items();
}
}, TimeUnit.SECONDS.toMillis(3), TimeUnit.SECONDS.toMillis(3));
}
public void get_items(){
Client client = ServiceGenerator.createService(Client.class,getBaseContext());
final Call<List<Items>> call = Client.getItems("items");
call.enqueue(new Callback<List<Items>>() {
#Override
public void onResponse(Call<List<Items>> call, Response<List<Items>> response) {
List<Items> items = response.body();
ItemsAdapter adapter = new ItemsAdapter(items);
recyclerView = findViewById(R.id.chatrecycler);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(Activity.this, LinearLayoutManager.VERTICAL,true));
}
#Override
public void onFailure(Call<List<Items>> call, Throwable t) {
}
});
}
And every 3 seconds the list updates but it starts from beginning.
What should I do to keep the position of the list during update??
You should not create new RecyclerView object in every api call. Also you are assigning adapter and LayoutManager with yout RecycletView in each call.
You just need to setAdapter with your RecycletView once and then second time just add new data in your adapter list and notify your adapter to refresh.
Please check below code.
private ItemsAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
recyclerView = findViewById(R.id.chatrecycler);
recyclerView.setLayoutManager(new LinearLayoutManager(SingleChat.this, LinearLayoutManager.VERTICAL,true));
get_items();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
synchronized public void run() {
get_items();
}
}, TimeUnit.SECONDS.toMillis(3), TimeUnit.SECONDS.toMillis(3));
}
public void get_items(){
Client client = ServiceGenerator.createService(Client.class,getBaseContext());
final Call<List<Items>> call = Client.getItems("items");
call.enqueue(new Callback<List<Items>>() {
#Override
public void onResponse(Call<List<Items>> call, Response<List<Items>> response) {
List<Items> items = response.body();
if(adapter == null) {
adapter = new ItemsAdapter(items);
recyclerView.setAdapter(adapter);
} else {
runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.addMoreItems(items);
adapter.notifyDatasetChanged();
}
});
}
}
#Override
public void onFailure(Call<List<SingleChatItem>> call, Throwable t) {
}
});
}
Add one method in your ItemsAdapter.java like,
public void addMoreItems(List<Items> items) {
this.items = items;
}
I have not tested this code myself.But it must work.Let me know if it doesn't.
final ItemsAdapter adapter = null;
ArrayList<Items> items = null;
recyclerView = findViewById(R.id.chatrecycler);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(Activity.this, LinearLayoutManager.VERTICAL,true));
call.enqueue(new Callback<List<Items>>() {
#Override
public void onResponse(Call<List<Items>> call, Response<List<Items>> response) {
List<Items> newItems = response.body();
if(adapter == null){
adapter = new ItemsAdapter(items);
items.addAll(newItems);
}else{
int i = 0;
for(Item item : items){
int index = newItems.indexOf(item);
item.stuff = newItems.get(index).stuff;
adapter.notifyItemChanged(i);
i++;
}
}
}
#Override
public void onFailure(Call<List<Items>> call, Throwable t) {
}
});

App crashes when fragment changes before volley response

I have bottom navigation view which has 3 fragments named Home, Notifications and Account. In Home fragment I am making volley post request that uses users last known location and on the basis of that it fetches response from the server. I want to know:
When I switch between the fragment before the volley response my app crashes and when I switch after response is complete there is no app crash.
Response from server is not showing when activity launches very first time.It shows when I switch between the fragments and come back to it again.
It is showing error log:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
at android.widget.Toast.<init>(Toast.java:138)
at android.widget.Toast.makeText(Toast.java:385)
at tiffino.app.com.Home$1.onResponse(Home.java:245)
at tiffino.app.com.Home$1.onResponse(Home.java:240)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:60)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:30)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Home.java
public class Home extends Fragment implements GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks,
com.google.android.gms.location.LocationListener {
TextView fragText;
GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
Location mLocation;
RequestQueue requestQueue;
StringRequest stringRequest;
public static final String TAG = "MyTag";
private static final String URL = "https://google.com";
public Home() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_home, container, false);
fragText = view.findViewById(R.id.fragText);
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
return view;
}
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
public void onStop() {
super.onStop();
if(mGoogleApiClient.isConnected() && requestQueue != null){
mGoogleApiClient.disconnect();
requestQueue.cancelAll(TAG);
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation != null) {
String str1 = hereLocation(mLocation.getLatitude(),mLocation.getLongitude());
fragText.setText(str1);
sendLocation(str1);
}
}
#Override
public void onConnectionSuspended(int i) { }
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) { }
private void sendLocation(final String str1) {
requestQueue = Volley.newRequestQueue(getContext());
stringRequest = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(getActivity(),""+response,Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) { }
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String,String> map = new HashMap<>();
map.put("name",str1);
return map;
}
};
stringRequest.setTag(TAG);
requestQueue.add(stringRequest);
}
private String hereLocation(double lat, double lon) {
String city = "";
Geocoder geo = new Geocoder(getContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = geo.getFromLocation(lat,lon,10);
if(addresses.size()>0) {
for (Address adr: addresses) {
if(adr.getLocality()!=null && adr.getLocality().length()>0) {
city = adr.getLocality();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return city;
}
}
Please let me know why app is crashing.
THANKS
The problem is probably with the getActivity() in the onRespones. The fragment isn't attached now to getActivity due to the fact that you are in another fragment now.
You can do:
if(isAdded()) {
Toast.makeText(getActivity(),""+response,Toast.LENGTH_SHORT).show();
}
letting the Activity implement the callback listeners is the most proper way to do it... because alike this one is always able to obtain the Context - no matter which Fragment is currently displayed.
public class MainActivity extends FragmentActivity implements Response.Listener, Response.ErrorListener {
...
#Override
public void onResponse(String response) {
if(response != null) {
Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onErrorResponse(VolleyError error) {
}
}
to be called alike this (from within the Fragment):
new StringRequest(Request.Method.GET, url, getActivity());
one could still pass that String back into the current Fragment, if required.
Although, You have not provided a piece of code. But generally I can tell you that you should take care of many things when you create a web request with some callback methods.
For example suppose you have the following piece of code:
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
mTextView.setText(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// Set the tag on the request.
stringRequest.setTag(TAG);
// Add the request to the RequestQueue.
queue.add(stringRequest);
It really depend on the logic of your application but for example one option is to totally cancel the request when the user leaves the current fragment. Therefore you can write the following code in the onStop() of your fragment:
#Override
protected void onStop () {
super.onStop();
if (queue!= null) {
queue.cancelAll(TAG);
}
}
Another option is to check for fragment status before you try to make the changes since the user might have left the fragment when your callback method is being called:
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if (isResumed())
{
mTextView.setText(response);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (isResumed())
{
mTextView.setText("That didn't work!");
}
}
});

onPause(); for SwipeRefreshLayout not working

i have a ViewPager with 3 lists in view pager and every list have an simple SwipeRefreshLayout its working well but when RefreshLayout is reffreshing and you press the back button (onPause i think?) the program will crashed andthe error is you cant set null object i know the problem i dont know how to fix it
pls help this is my code
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.activity_fragment1,container,false);
mListView = (ListView) view.findViewById(R.id.list_news);
refresh = (SwipeRefreshLayout) view.findViewById(R.id.refresh);
refresh.setColorSchemeColors(
R.color.material_green_200,
R.color.material_green_400,
R.color.material_green_600,
R.color.material_green_800
);
refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
String uri = "http://192.168.1.101/mySite/Flowers/flowers.json";
JsonArrayRequest request = new JsonArrayRequest(uri,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
JsonParser parser = new JsonParser();
ArrayList items = parser.parseJson(response);
FlowerAdapter adapter = new FlowerAdapter(getContext(),
R.layout.activity_last_news_fragment,items);
mListView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(), "error", Toast.LENGTH_SHORT).show();
}
});
RequestQueue quew = Volley.newRequestQueue(getActivity().getApplicationContext());
quew.add(request);
refresh.setRefreshing(false);
}
});
String uri = "http://192.168.1.101/mySite/Flowers/flowers.json";
JsonArrayRequest request = new JsonArrayRequest(uri,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
JsonParser parser = new JsonParser();
ArrayList items = parser.parseJson(response);
FlowerAdapter adapter = new FlowerAdapter(getContext(),
R.layout.activity_last_news_fragment,items);
mListView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(), "error", Toast.LENGTH_SHORT).show();
}
});
RequestQueue quew = Volley.newRequestQueue(getActivity().getApplicationContext());
quew.add(request);
return view;
}
#Override
public void onPause() {
if (refresh.isRefreshing()){
refresh.setEnabled(false);
}else {
super.onPause();
}
}
how can i override onpause method to when it called first stop refreshing then pause?
and this is compelete error Log
12-07 17:11:41.942 13992-13992/app.mma.introsliderproject E/AndroidRuntime: FATAL EXCEPTION: main
Process: app.mma.introsliderproject, PID: 13992
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.support.v4.app.FragmentActivity.getApplicationContext()' on a null object reference
at app.mma.PokerInfo.twitch.TwitchFragment$2.onResponse(TwitchFragment.java:73)
at app.mma.PokerInfo.twitch.TwitchFragment$2.onResponse(TwitchFragment.java:67)
at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:65)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7409)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
This is causing issue Volley.newRequestQueue(getActivity().getApplicationContext()); inside onRefresh(). You will need to check is your activity is in running state i.e is the context null or not.
#Override
public void onRefresh () {
if (YourFragment.this.isVisible()) {
String uri = "http://192.168.1.101/mySite/Flowers/flowers.json";
JsonArrayRequest request = new JsonArrayRequest(uri,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
JsonParser parser = new JsonParser();
ArrayList items = parser.parseJson(response);
FlowerAdapter adapter = new FlowerAdapter(getContext(),
R.layout.activity_last_news_fragment,items);
mListView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(), "error", Toast.LENGTH_SHORT).show();
}
});
RequestQueue quew = Volley.newRequestQueue(getActivity().getApplicationContext());
quew.add(request);
refresh.setRefreshing(false);
}
}
Put everything inside if(){} to avoid crash

Refresh Listview of another fragment

I'm Using viewpager with 2 swiping tab layouts. In the first tablayout I post data to the server and when I switch the tab the Listview in not update. Only when I click on Listview Item and close it the Listview gets refreshed and the posted data is visible...
Question Is : How to automatically refresh Listview when data is posted to server can some one help please.
public class PagerAdapter extends FragmentStatePagerAdapter {
int numOfTabs;
public PagerAdapter(FragmentManager fm,int numOfTabs) {
super(fm);
this.numOfTabs=numOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
RaiseComplaintFragment RFragment=new RaiseComplaintFragment();
return RFragment;
case 1:
ComplaintListFragment CFragment=new ComplaintListFragment();
return CFragment;
default:
return null;
}
}
#Override
public int getCount() {
return numOfTabs;
}
}
This is the method which posts data to the server
public void postDataToServer(String complaintdata) throws JSONException {
String url = URLMap.getPostComplaintUrl();
String roleId = LoggedInUserStore.getLoggedInRoleId(getContext());
String branchId = LoggedInUserStore.getLoggedInBranchId(getContext());
String compid = LoggedInUserStore.getLoggedInCompanyId(getContext());
HashMap<String, String> params = new HashMap<>();
params.put("CallRecordID", "0"); //pass 0 if we are inserting a new record always
params.put("CompanyID", compid);
params.put("BranchID", branchId);
params.put("ServiceID", sId);
params.put("CallLocationID", lId);
params.put("RaisedByID", roleId);
params.put("ComplaintDetails", complaintdata);
params.put("CallStatusID", "1");
pDialog = new ProgressDialog(getContext());
pDialog.setMessage("Please wait..");
pDialog.setProgressStyle(pDialog.STYLE_SPINNER);
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
JsonObjectRequest req = new JsonObjectRequest(url, new JSONObject(params), new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Complaint has been registered successfully");
builder.setMessage("").setCancelable(true);
AlertDialog alertDialog = builder.create();
alertDialog.show();
_complaintText.setText("");
serviceSpinner.setSelection(0);
locationSpinner.setSelection(0);
pDialog.dismiss();
/*((HomeActivity)getActivity()).getViewPager().setCurrentItem(1); //onCLick of Submit it just switches the tab
String tagName="android:switcher:"+R.id.pager+":"+1;
ComplaintListFragment f2=(ComplaintListFragment)getActivity().getSupportFragmentManager().findFragmentByTag(tagName);
f2.fetchComplaintData();*/
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Unable to register your request.\nPlease try later.");
builder.setCancelable(true);
AlertDialog alertDialog = builder.create();
alertDialog.show();
pDialog.dismiss();
}
});
req.setRetryPolicy(new VolleyRetryPolicy().getRetryPolicy());
RequestQueue requestQueue = ((VolleyRequestQueue) getActivity().getApplication()).getRequestQueue();
requestQueue.add(req);
}
My HomeActivity class which handles two tab layouts
viewPager = (ViewPager) findViewById(R.id.view_Pager);
tabLayout = (TabLayout) findViewById(R.id.tab_Layout);
String roleID = LoggedInUserStore.getLoggedInRoleId(getApplicationContext());
if (roleID.equals("4")) {
//RAISE COMPLAINT UI. IF ROLE ID == 4 MANAGER DASHBOARD
tabLayout.addTab(tabLayout.newTab().setText("Raise Complaint"));
tabLayout.addTab(tabLayout.newTab().setText("Complaint List"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final PagerAdapter adapter =
new com.six30labs.cms.adapters.PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
Second fragment which contains my listview
public class ComplaintListFragment extends Fragment {
private ListView complaintListView;
EditText _inputSearch;
ComplaintAdapter compadapter;
private static Parcelable mListViewScrollPos = null;
private RequestQueue mQueue;
ProgressBar progressBar;
String URL;
private View v;
String TAG="Second Fragment";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.fragment_complaint_list, container, false);
complaintListView = (ListView) v.findViewById(R.id.complaintListView);
_inputSearch = (EditText) v.findViewById(R.id.inputSearchforComplaintListFragment);
progressBar = (ProgressBar) v.findViewById(R.id.complaintListProgressBar);
fetchComplaintData();
_inputSearch.addTextChangedListener(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) {
try {
compadapter.getFilter().filter(s.toString());
compadapter.notifyDataSetChanged();
}catch (NullPointerException e){
e.printStackTrace();
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
if (mListViewScrollPos != null) {
complaintListView.onRestoreInstanceState(mListViewScrollPos);
}
return v;
}
public void fetchComplaintData() {
progressBar.setVisibility(View.VISIBLE);
URL = URLMap.getComplaintUrl("complaint_url");
URL = URL.replace("{id}", LoggedInUserStore.getLoggedInCompanyId(getContext()));
StringRequest request = new StringRequest(Request.Method.GET,URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
getCompliantList(response);
progressBar.setVisibility(View.GONE);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(), error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
request.setRetryPolicy(new VolleyRetryPolicy().getRetryPolicy());
RequestQueue queue=((VolleyRequestQueue)getActivity().getApplication()).getRequestQueue();
queue.add(request);
/* RequestQueue requestQueue
= Volley.newRequestQueue(getContext());
requestQueue.add(request);*/
}
public void getCompliantList(String response) {
try {
List complaint = new ArrayList<>();
JSONArray jArray = new JSONArray(response);
for (int i = 0; i < jArray.length(); i++) {
// complaint.add(Complaint.fromJson(jArray.getJSONObject(i)));
complaint.add(0,Complaint.fromJson(jArray.getJSONObject(i))); //To push the data to the top of the listview.
}
compadapter = new ComplaintAdapter(getContext(), complaint);
complaintListView.setAdapter(compadapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
//Method that will save the position the user when they scroll
//return it when the user comes back to the listView instead of it refreshing the data.
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mListViewScrollPos = complaintListView.onSaveInstanceState();
}
public void onPause() {
super.onPause();
}
public void onResume() {
super.onResume();
fetchComplaintData();
}
BroadcastReceiver For class Where your Listview is
private BroadcastReceiver updateProfileBroadcast = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Fire your event
}
};
Register Broadcast in onResume()
registerReceiver(updateProfileBroadcast, new IntentFilter("KEY"));
Now fire Broadcast From Fragment
Intent intent = new Intent("KEY");
getActivity().sendBroadcast(intent);
As an alternative to SID's answer you may use EventBus. It works by event-driven architecture and able to transfer information between components really easy and fast.
That's how you use it:
1) add to project in app gradle: compile 'org.greenrobot:eventbus:3.0.0'
2) Register EventBus in fragment's onCreate() where you need to update ListView: eventBus.register(this);. And don't forget to unregister it on onDestryView(): eventBus.unregister(this);
3) Add the method to your ListView fragment which will handle event with list update:
#SupressWarning("unused")
#Subscribe
public void onEvent(List<YourListViewData> event) {/* update `ListView` */};
4) Fire that event from activity\fragment when you need to update ListView:
EventBus bus = EventBus.getInstance();
eventBus.post(List<YourListViewData> yourData);

Categories

Resources