Swipe/Pull to Refresh for Android RecyclerView - android

I have created an app to get RSS Feed from XML file and show it in a recyclerview within card views. I want to implement the Pull to refresh to load the data.
where exactly the method supposed to be ?
my main activity :
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
//Call Read rss asyntask to fetch rss
try {
ReadRss readRss = new ReadRss(this, recyclerView);
readRss.execute();
}catch (Exception e) {
Toast.makeText(getApplicationContext(), "There's a problem", Toast.LENGTH_LONG);
}
}
}
and this is ReadRss class :
public class ReadRss extends AsyncTask<Void, Void, Void> {
Context context;
String address = "http://karary-001-site1.htempurl.com/XMLFile1.xml";
ProgressDialog progressDialog;
ArrayList<FeedItem> feedItems;
RecyclerView recyclerView;
URL url;
public ReadRss(Context context, RecyclerView recyclerView) {
this.recyclerView = recyclerView;
this.context = context;
progressDialog = new ProgressDialog(context);
progressDialog.setMessage("loading....");
}
//before fetching of rss statrs show progress to user
#Override
protected void onPreExecute() {
progressDialog.show();
super.onPreExecute();
}
//This method will execute in background so in this method download rss feeds
#Override
protected Void doInBackground(Void... params) {
//call process xml method to process document we downloaded from getData() method
ProcessXml(Getdata());
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
progressDialog.dismiss();
FeedsAdapter adapter = new FeedsAdapter(context, feedItems);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.addItemDecoration(new VerticalSpace(20));
recyclerView.setAdapter(adapter);
}
pullToRefresh method :
final SwipeRefreshLayout pullToRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
//refresh code
pullToRefresh.setRefreshing(false);
}
});
where exactly the method supposed to be ?

First set pullToRefresh.setRefreshing(true); if its not working than try below code
pullToRefresh.post(new Runnable() {
#Override
public void run() {
pullToRefresh.setRefreshing(true);
}
});

Here is what you can do
pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
//refresh code
ReadRss readRss = new ReadRss(this, recyclerView);
readRss.execute();
}
});
and then in onPostExeceute()
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
progressDialog.dismiss();
pullToRefresh.setRefreshing(false); // in case of pullToRefresh
FeedsAdapter adapter = new FeedsAdapter(context, feedItems);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.addItemDecoration(new VerticalSpace(20));
recyclerView.setAdapter(adapter);
}
Hope this helps

Related

Recyclerview Position changing to first position when I Update

I am using onLoadMoreListener when i scroll RecyclerView. It will update the RecyclerView data when you scroll to bottom. After updating the Recyclerview data. The Recyclerview goes back up to the top. Ideally, I would like to retain the position in the RecyclerView. Any thoughts on how I should go about doing this?
mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
new GroupData().execute();
}
});
InnerClass
public static class GroupData extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
try{
GroupList gm = new GroupList();
.....
groupvalues.add(gm);
} catch (Exception e){
Log.d("Grouplist ", e.toString());
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
mAdapter = new GroupAdapter(groupvalues,mrecyclerview);
mrecyclerview.setAdapter(mAdapter);
progressDialog.dismiss();
mAdapter.notifyDataSetChanged();
}
}
}
Try this,
public static class GroupData extends AsyncTask<Void, Void, Void> {
int size = 0;
#Override
protected void onPreExecute() {
size = groupvalues.size();
}
#Override
protected Void doInBackground(Void... voids) {
try {
GroupList gm = new GroupList();
.....
groupvalues.add(gm);
} catch (Exception e) {
Log.d("Grouplist ", e.toString());
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
mAdapter.notifyItemRangeChanged(size, groupvalues.size() - size);
progressDialog.dismiss();
}
}
When you are loading you must be knowing the position of top element of new loaded items. just call:
recyclerView.scrollToPosition(position);
or just save the last know position of your recyclerView and Scroll to that position when you load more items
Just notify your adapter in onPostExecute. No need to initialise your adapter again.
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
progressDialog.dismiss();
mAdapter.notifyDataSetChanged();
}
Initialise your adapter in onCreate
mAdapter = new GroupAdapter(groupvalues,mrecyclerview);
mrecyclerview.setAdapter(mAdapter);

How to reload Volley data to get current items from json

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);
}
});

Cannot resolve symbol 'adapter'

I receive an error with the following code. I don't understand why, but adapter.notifyDataSetChanged(); doesn't work. The message of error is: "cannot resolve symbol 'adapter'".
final String URL = "http://example....";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rv = (RecyclerView) findViewById(R.id.rv);
....
public class PrintA extends AsyncTask<String, String, List<Model>> {
....
#Override
protected void onPostExecute(final List<MyModel> result) {
super.onPostExecute(result);
if (result != null) {
MyAdapter adapter = new MyAdapter(result);
rv.setAdapter(adapter);
} else {
Toast.makeText(getApplicationContext(), "no internet",
}
}
}
new PrintA().execute(URL);
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
....
public class PrintB extends AsyncTask<String, String, List<Model>> {
....
#Override
protected void onPostExecute(final List<MyModel> result) {
super.onPostExecute(result);
if (result != null) {
....
adapter.notifyDataSetChanged();
} else {
Toast.makeText(getApplicationContext(), "can't add",
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
....
new PrintB().execute(URL);
}
}
}
}
MyAdapter adapter = new MyAdapter(result);
replace this by
adapter = new MyAdapter(result);
and declare this in Global
MyAdapter adapter;
like this
MyAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {

Empty ListView after reshresh SwipeRefreshLayout

I try to use SwipeRefreshLayout with ListView.
ListView and ArrayAdapter works well when i try to load data first time.
But, when i try to refresh - i have empty ListView (but array have data).
Here some code:
MainActivity:
final SwipeRefreshLayout swipe= (SwipeRefreshLayout) findViewById(R.id.swipe);
_loader=new RssLoader(getApplicationContext(),this,swipe);
swipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
_loader.loadFeeds();
}
});
Loader class:
public void loadFeeds() {
String[] urlArr = {"http://www.example.com/export/news.xml"};
new RssReader(_context)
.showDialog(false)
.urls(urlArr)
.parse(new OnRssLoadListener() {
#Override
public void onSuccess(List<RssItem> rssItems) {
ArrayList<String> titles=new ArrayList<>();
if(rssItems.size()!=0)
{
titles.clear();
RssItems.clear();
}
Toast.makeText(_context, rssItems.get(0).getTitle(), Toast.LENGTH_SHORT).show();
for (RssItem item:rssItems
) {
RssItems.add(item);
titles.add(item.getTitle());
Log.i("Item:",item.getTitle());
}
ArrayAdapter<String> adapter=new ArrayAdapter<String>(_context,R.layout.support_simple_spinner_dropdown_item,titles);
ListView listNewNews= (ListView) _activity.findViewById(R.id.listViewNews);
listNewNews.setAdapter(adapter);
if(_swipeRefresh!=null) {
_swipeRefresh.setRefreshing(false);
}
}
#Override
public void onFailure(String message) {
Toast.makeText(_context, "Error: "+message, Toast.LENGTH_SHORT).show();
}
});
}

Parse.com show progress dialog on loading

I'm using Parse.com and I'm trying to show a progress while the data loads into my gridview. Check out my attempt below. The progress bar never show up. It just show a white screen then starts showing gridview items.
rListActivity.java
public class rListActivity extends Activity {
pAdapter padapter;
GridView gridview;
ProgressDialog mProgressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_main);
gridview = (GridView) findViewById(R.id.gridview);
padapter = new pAdapter(this);
padapter.loadObjects();
padapter.addOnQueryLoadListener(new ParseQueryAdapter.OnQueryLoadListener<Meal>() {
#Override
public void onLoading() {
mProgressDialog = new ProgressDialog(rListActivity.this);
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
public void onLoaded(List<Meal> objects, Exception e) {
gridview.setAdapter(padapter);
mProgressDialog.dismiss();
}
});
}
pAdapter.java
public class pAdapter extends ParseQueryAdapter<Meal> {
public pAdapter(Context context) {
super(context, new ParseQueryAdapter.QueryFactory<Meal>() {
public ParseQuery<Meal> create() {
ParseQuery query = new ParseQuery("Meal");
query.orderByAscending("title");
return query;
}
});
}
......
Itemviews....
I might be late but the answer is very easy.
You need to call padapter.loadObjects(); after
padapter.addOnQueryLoadListener(new ParseQueryAdapter.OnQueryLoadListener<Meal>() {
#Override
public void onLoading() {
mProgressDialog = new ProgressDialog(rListActivity.this);
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
public void onLoaded(List<Meal> objects, Exception e) {
gridview.setAdapter(padapter);
mProgressDialog.dismiss();
}
});

Categories

Resources