Skip to content

Commit

Permalink
full source commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sab99r committed Jul 7, 2016
1 parent 6c13259 commit df56e02
Show file tree
Hide file tree
Showing 13 changed files with 392 additions and 13 deletions.
27 changes: 27 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 24
compileSdkVersion 23
buildToolsVersion "23.0.3"

defaultConfig {
applicationId "com.sab99r.recyclerview_loadmore"
minSdkVersion 10
targetSdkVersion 24
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
Expand All @@ -22,5 +22,9 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:appcompat-v7:23.0.0'
compile 'com.android.support:recyclerview-v7:23.0.0'
// network
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
}
107 changes: 107 additions & 0 deletions app/src/main/java/com/sab99r/recyclerview_loadmore/MainActivity.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,120 @@
package com.sab99r.recyclerview_loadmore;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;

import com.sab99r.recyclerview_loadmore.network.MoviesApi;
import com.sab99r.recyclerview_loadmore.network.ServiceGenerator;

import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

RecyclerView recyclerView;
List<MovieModel> movies;
MoviesAdapter adapter;
MoviesApi api;
String TAG = "MainActivity - ";
Context context;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
movies = new ArrayList<>();

adapter = new MoviesAdapter(this, movies);
adapter.setLoadMoreListener(new MoviesAdapter.OnLoadMoreListener() {
@Override
public void onLoadMore() {

recyclerView.post(new Runnable() {
@Override
public void run() {
int index = movies.size() - 1;
loadMore(index);
}
});
//Calling loadMore function in Runnable to fix the
// java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling error
}
});
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.addItemDecoration(new VerticalLineDecorator(2));
recyclerView.setAdapter(adapter);

api = ServiceGenerator.createService(MoviesApi.class);
load(0);
}

private void load(int index){
Call<List<MovieModel>> call = api.getMovies(index);
call.enqueue(new Callback<List<MovieModel>>() {
@Override
public void onResponse(Call<List<MovieModel>> call, Response<List<MovieModel>> response) {
if(response.isSuccessful()){
movies.addAll(response.body());
adapter.notifyDataChanged();
}else{
Log.e(TAG," Response Error "+String.valueOf(response.code()));
}
}

@Override
public void onFailure(Call<List<MovieModel>> call, Throwable t) {
Log.e(TAG," Response Error "+t.getMessage());
}
});
}

private void loadMore(int index){

//add loading progress view
movies.add(new MovieModel("load"));
adapter.notifyItemInserted(movies.size()-1);

Call<List<MovieModel>> call = api.getMovies(index);
call.enqueue(new Callback<List<MovieModel>>() {
@Override
public void onResponse(Call<List<MovieModel>> call, Response<List<MovieModel>> response) {
if(response.isSuccessful()){

//remove loading view
movies.remove(movies.size()-1);

List<MovieModel> result = response.body();
if(result.size()>0){
//add loaded data
movies.addAll(result);
}else{//result size 0 means there is no more data available at server
adapter.setMoreDataAvailable(false);
//telling adapter to stop calling load more as no more server data available
Toast.makeText(context,"No More Data Available",Toast.LENGTH_LONG).show();
}
adapter.notifyDataChanged();
//should call the custom method adapter.notifyDataChanged here to get the correct loading status
}else{
Log.e(TAG," Load More Response Error "+String.valueOf(response.code()));
}
}

@Override
public void onFailure(Call<List<MovieModel>> call, Throwable t) {
Log.e(TAG," Load More Response Error "+t.getMessage());
}
});
}
}
16 changes: 16 additions & 0 deletions app/src/main/java/com/sab99r/recyclerview_loadmore/MovieModel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sab99r.recyclerview_loadmore;

import java.io.Serializable;

/**
* Created by sab99r
*/
public class MovieModel implements Serializable{
String title;
String rating;
String type;

public MovieModel(String type) {
this.type = type;
}
}
117 changes: 117 additions & 0 deletions app/src/main/java/com/sab99r/recyclerview_loadmore/MoviesAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.sab99r.recyclerview_loadmore;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;

/**
* Created by sab99r
*/
public class MoviesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

public final int TYPE_MOVIE = 0;
public final int TYPE_LOAD = 1;

static Context context;
List<MovieModel> movies;
OnLoadMoreListener loadMoreListener;
boolean isLoading = false, isMoreDataAvailable = true;

/*
* isLoading - to set the remote loading and complete status to fix back to back load more call
* isMoreDataAvailable - to set whether more data from server available or not.
* It will prevent useless load more request even after all the server data loaded
* */


public MoviesAdapter(Context context, List<MovieModel> movies) {
this.context = context;
this.movies = movies;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType==TYPE_MOVIE){
return new MovieHolder(inflater.inflate(R.layout.row_movie,parent,false));
}else{
return new LoadHolder(inflater.inflate(R.layout.row_load,parent,false));
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

if(position>=getItemCount()-1 && isMoreDataAvailable && !isLoading && loadMoreListener!=null){
isLoading = true;
loadMoreListener.onLoadMore();
}

if(getItemViewType(position)==TYPE_MOVIE){
((MovieHolder)holder).bindData(movies.get(position));
}
//No else part needed as load holder doesn't bind any data
}

@Override
public int getItemViewType(int position) {
if(movies.get(position).type.equals("movie")){
return TYPE_MOVIE;
}else{
return TYPE_LOAD;
}
}

@Override
public int getItemCount() {
return movies.size();
}

/* VIEW HOLDERS */

static class MovieHolder extends RecyclerView.ViewHolder{
TextView tvTitle;
TextView tvRating;
public MovieHolder(View itemView) {
super(itemView);
tvTitle=(TextView)itemView.findViewById(R.id.title);
tvRating=(TextView)itemView.findViewById(R.id.rating);
}

void bindData(MovieModel movieModel){
tvTitle.setText(movieModel.title);
tvRating.setText("Rating "+movieModel.rating);
}
}

static class LoadHolder extends RecyclerView.ViewHolder{
public LoadHolder(View itemView) {
super(itemView);
}
}

public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}

/* notifyDataSetChanged is final method so we can't override it
call adapter.notifyDataChanged(); after update the list
*/
public void notifyDataChanged(){
notifyDataSetChanged();
isLoading = false;
}


interface OnLoadMoreListener{
void onLoadMore();
}

public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.sab99r.recyclerview_loadmore;

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
* Created by sab99r
*/
public class VerticalLineDecorator extends RecyclerView.ItemDecoration {
private int space=0;

public VerticalLineDecorator(int space) {
this.space = space;
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

if(parent.getChildAdapterPosition(view) == 0)
outRect.top = space;

outRect.bottom = space;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.sab99r.recyclerview_loadmore.network;

import com.sab99r.recyclerview_loadmore.MovieModel;

import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
/**
* Created by sab99r
*/
public interface MoviesApi {
@GET("movies.php")
Call<List<MovieModel>> getMovies(@Query("index") int index);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.sab99r.recyclerview_loadmore.network;

import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by sab99r
*/
public class ServiceGenerator {

public static <S> S createService(Class<S> serviceClass) {

OkHttpClient httpClient=new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.sab99r.com/demos/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient).build();

return retrofit.create(serviceClass);

}

}
Loading

0 comments on commit df56e02

Please sign in to comment.