I have implemented recyclerview using cardview to fetch images and text from my server using this tutorial: http://www.simplifiedcoding.net/android-custom-listview-with-images-using-recyclerview-and-volley/.
I have successfully fetched the data and modified the code according to my requirement, now i want to implement swipe to refresh and endless scrolling similar to Instagram application. I have tried a lot of tutorials and SO questions however i am unable to implement any of them.
I am partially successfully implementing swipe-to-refresh but the app exits with an inconsistency error
. kindly guide
MainActivity.java
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener{
SwipeRefreshLayout swipeLayout;
LinearLayoutManager mLayoutManager;
// initially offset will be 0, later will be updated while parsing the json
private int offSet = 0;
private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;
//Creating a List of superheroes
private List<SuperHeroes> listSuperHeroes;
//Creating Views
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
public String Img;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Initializing Views
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
//Initializing our superheroes list
listSuperHeroes = new ArrayList<>();
mLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutManager);
swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
swipeLayout.setOnRefreshListener(this);
swipeLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
swipeLayout.post(new Runnable() {
@Override
public void run() {
swipeLayout.setRefreshing(true);
getData();
}
}
);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) //check for scroll down
{
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
Log.v("...", "Last Item Wow !");
//Do pagination.. i.e. fetch new data
loading = true;
}
}
}
}
});
}
//This method will get data from the web api
private void getData(){
//Showing a progress dialog
// final ProgressDialog loading = ProgressDialog.show(this,"Loading Data", "Please wait...",false,false);
// appending offset to url
String url = Config.DATA_URL;
String url1 = url + offSet;
//Creating a json array request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url1,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
//Dismissing progress dialog
// loading.dismiss();
//calling method to parse json array
parseData(response);
adapter.notifyDataSetChanged();
// stopping swipe refresh
swipeLayout.setRefreshing(false);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
//Creating request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//Adding request to the queue
requestQueue.add(jsonArrayRequest);
}
//This method will parse json data
private void parseData(JSONArray array){
for(int i = 0; i<array.length(); i++) {
SuperHeroes superHero = new SuperHeroes();
CardAdapter car = new CardAdapter();
JSONObject json = null;
try {
json = array.getJSONObject(i);
superHero.setImageUrl(json.getString(Config.TAG_IMAGE_URL));
Img =json.getString(Config.TAG_IMAGE_URL);
superHero.setName(json.getString(Config.TAG_NAME));
superHero.setRank(json.getInt(Config.TAG_RANK));
// superHero.setRealName(json.getString(Config.TAG_REAL_NAME));
//superHero.setCreatedBy(json.getString(Config.TAG_CREATED_BY));
//superHero.setFirstAppearance(json.getString(Config.TAG_FIRST_APPEARANCE));
int rank = json.getInt("pid");
// updating offset value to highest value
if (rank >= offSet)
offSet = rank;
// ArrayList<String> powers = new ArrayList<String>();
//JSONArray jsonArray = json.getJSONArray(Config.TAG_POWERS);
/* for(int j = 0; j<jsonArray.length(); j++){
powers.add(((String) jsonArray.get(j))+"\n");
}*/
//superHero.setPowers(powers);
Log.d("test",Img);
car.setImageUrl(Img);
} catch (JSONException e) {
e.printStackTrace();
}
listSuperHeroes.add(superHero);
}
//Finally initializing our adapter
adapter = new CardAdapter(listSuperHeroes, this);
//Adding adapter to recyclerview
recyclerView.setAdapter(adapter);
}
@Override
public void onRefresh() {
listSuperHeroes.clear();
getData();
}
}
CardAdapter.java
/**
* Created by Belal on 11/9/2015.
*/
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
private String imageUrl;
private ImageLoader imageLoader;
private Context context;
String Load;
static int count = 0;
public static final String uu = "uu";
String number;
String user1;
public static final String UserNum = "UserNum";
SharedPreferences sharedPref;
// JSON parser class
JSONParser jsonParser = new JSONParser();
//testing from a real server:
private static final String LIKE_URL = "myurl";
//ids
private static final String TAG_SUCCESS = "success";
private static final String TAG_MESSAGE = "message";
//List of superHeroes
List<SuperHeroes> superHeroes;
public CardAdapter() {
}
public CardAdapter(List<SuperHeroes> superHeroes, Context context) {
super();
//Getting all the superheroes
this.superHeroes = superHeroes;
this.context = context;
sharedPref =context.getSharedPreferences(UserNum, 0);
number = sharedPref.getString(uu, "");
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.superheroes_list, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
SuperHeroes superHero = superHeroes.get(position);
Log.d("position", String.valueOf(position));
Log.d("url", superHero.getImageUrl());
imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();
imageLoader.get(superHero.getImageUrl(), ImageLoader.getImageListener(holder.imageView, R.mipmap.ic_launcher, android.R.drawable.ic_dialog_alert));
holder.imageView.setImageUrl(superHero.getImageUrl(), imageLoader);
holder.textViewName.setText(superHero.getName());
holder.textViewRank.setText(String.valueOf(superHero.getRank()));
// holder.textViewRealName.setText(superHero.getRealName());
// holder.textViewCreatedBy.setText(superHero.getCreatedBy());
// holder.textViewFirstAppearance.setText(superHero.getFirstAppearance());
// Load =superHero.getImageUrl();
// String powers = "";
// for(int i = 0; i<superHero.getPowers().size(); i++){
// powers+= superHero.getPowers().get(i);
// }
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
count++;
ViewHolder h = (ViewHolder) view.getTag();
// int p=h.getAdapterPosition();
SuperHeroes s = superHeroes.get(position);
// Toast.makeText(context,s.getImageUrl(),Toast.LENGTH_LONG).show();
Load = s.getImageUrl();
Log.d("test", Load);
String s1 = new Integer(count).toString();
Log.d("count", s1);
new LikeIt().execute();
}
};
// holder.textViewPowers.setText(powers);
holder.like.setOnClickListener(clickListener);
}
@Override
public int getItemCount() {
return superHeroes.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public NetworkImageView imageView;
public TextView textViewName;
public TextView textViewRank;
public TextView textViewRealName;
public TextView textViewCreatedBy;
public TextView textViewFirstAppearance;
public TextView textViewPowers;
public Button like;
public ViewHolder(View itemView) {
super(itemView);
imageView = (NetworkImageView) itemView.findViewById(R.id.imageViewHero);
textViewName = (TextView) itemView.findViewById(R.id.textViewName);
textViewRank = (TextView) itemView.findViewById(R.id.textViewRank);
// textViewRealName= (TextView) itemView.findViewById(R.id.textViewRealName);
// textViewCreatedBy= (TextView) itemView.findViewById(R.id.textViewCreatedBy);
// textViewFirstAppearance= (TextView) itemView.findViewById(R.id.textViewFirstAppearance);
// textViewPowers= (TextView) itemView.findViewById(R.id.textViewPowers);
like = (Button) itemView.findViewById(R.id.button_like);
}
}
class LikeIt extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
*/
boolean failure = false;
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... args) {
// TODO Auto-generated method stub
// Check for success tag
int success;
String Imgurl = Load;
Log.d("request!", number);
// try {
// Building Parameters
HashMap<String, String> Params = new HashMap<String, String>();
Params.put("Imgurl", Imgurl);
Params.put("user", number);
Log.d("request!", "starting");
//Posting user data to script
/* JSONObject json = jsonParser.performPostCall(LIKE_URL,Params);
// full json response
Log.d("Login attempt", json.toString());
// json success element
success = json.getInt(TAG_SUCCESS);
if (success == 1) {
Log.d("User Created!", json.toString());
//finish();
return json.getString(TAG_MESSAGE);
}else{
Log.d("Login Failure!", json.getString(TAG_MESSAGE));
return json.getString(TAG_MESSAGE);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;*/
String encodedStr = getEncodedData(Params);
//Will be used if we want to read some data from server
BufferedReader reader = null;
//Connection Handling
try {
//Converting address String to URL
URL url = new URL(LIKE_URL);
//Opening the connection (Not setting or using CONNECTION_TIMEOUT)
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//Post Method
con.setRequestMethod("POST");
//To enable inputting values using POST method
//(Basically, after this we can write the dataToSend to the body of POST method)
con.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream());
//Writing dataToSend to outputstreamwriter
writer.write(encodedStr);
//Sending the data to the server - This much is enough to send data to server
//But to read the response of the server, you will have to implement the procedure below
writer.flush();
//Data Read Procedure - Basically reading the data comming line by line
StringBuilder sb = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
while((line = reader.readLine()) != null) { //Read till there is something available
sb.append(line + "\n"); //Reading and saving line by line - not all at once
}
line = sb.toString(); //Saving complete data received in string, you can do it differently
//Just check to the values received in Logcat
Log.i("custom_check","The values :");
Log.i("custom_check",line);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(reader != null) {
try {
reader.close(); //Closing the
} catch (IOException e) {
e.printStackTrace();
}
}
}
//Same return null, but if you want to return the read string (stored in line)
//then change the parameters of AsyncTask and return that type, by converting
//the string - to say JSON or user in your case
return null;
}
}
private String getEncodedData(Map<String,String> data) {
StringBuilder sb = new StringBuilder();
for(String key : data.keySet()) {
String value = null;
try {
value = URLEncoder.encode(data.get(key), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if(sb.length()>0)
sb.append("&");
sb.append(key + "=" + value);
}
return sb.toString();
}
/**
* After completing background task Dismiss the progress dialog
**/
protected void onPostExecute() {
// dismiss the dialog once product deleted
}
}
During swipe on refresh if i scroll down immediately after refresh the app crashes but if i wait till refresh happens i do not get the inconsistency error
Logcat error
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: FATAL EXCEPTION: main
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: Process: com.example.tatson.bila, PID: 14987
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{278460a2 position=3 id=-1, oldPos=-1, pLpos:-1 no parent}
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4247)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4378)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4359)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1161)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1018)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:3807)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.view.Choreographer.doCallbacks(Choreographer.java:580)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.view.Choreographer.doFrame(Choreographer.java:549)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:739)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.os.Looper.loop(Looper.java:135)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5253)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:372)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
11-21 16:04:28.209 14987-14987/com.example.tatson.bila E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
also the load on scroll gets activated when i scroll to the end quickly and not when i am on the last item and scroll down
Thank You in advance!!! :)