Good day, so my problem as follows.
When I initialize the retrofit call it has following flow.
1.In the Presenterclass, it goes to getData method.
2.Then it goes to Interactorclass and creates a instance of itself.
3.Then it starts to fetch data from getMovieList method.
4.When it gets to call.enqueue it says OnDataCallback is null.
5.Goes back to Presenter and returns a null List.
6.It resumes call.enqueue does the api call as required.
7.Returns to Presenter and returns the List of objects.
I have tried so many things but non seem to work, maybe I'm understanding something incorrectly ,any help would be appreciated thanks.
Interactor Class.
public class MovieListInteractor implements IMovieContarctor.MovieListInteractor {
private InteractorListener mListener;
private List<MovieListModel> mList;
public MovieListInteractor(InteractorListener mListener) {
this.mListener = mListener;
}
public int getMovieSize() {
return mList.size();
}
#Override
public String getMoviePosterPath(int pos) {
return mList.get(pos).getPosterPath();
}
#Override
public MovieListModel getMovie(int pos) {
return mList.get(pos);
}
#Override
public List<MovieListModel> getMovieList() {
if (mList == null)
mList = new ArrayList<>();
ServerMovieCall mCall = new ServerMovieCall();
mCall.getMovieList(new IOnDataCallback<List<MovieListModel>>() {
#Override
public void onSuccess(List<MovieListModel> data) {
mList.addAll(data);
}
#Override
public void onFailure(String message) {
Log.d(TAG, "onFailure: " + message);
}
});
return mList;
}
}
Presenter class
public class MovieListPresenter implements IMovieContarctor.MovieListPresenter, InteractorListener {
private MovieListFragment mView;
private MovieListInteractor mInteractor;
private List<MovieListModel> mList;
public MovieListPresenter(MovieListFragment mView) {
this.mView = mView;
mInteractor = new MovieListInteractor(this);
getData();
}
//TODO: Add functionality so that the view could call mView.refreshAdapterList
//TODO: And from the view - adapter.notifiyDataSetChange;
#Override
public void onSuccess(List<MovieListModel> data, String msg) {
mView.onDataChange(data, msg);
}
#Override
public void onFailure(String msg) {
mView.onDataFailure(msg);
}
#Override
public void bindAtPosition(int position, MovieListViewHolder holder) {
holder.setValue(mInteractor.getMovie(position));
}
#Override
public void getData() {
mList = mInteractor.getMovieList();
}
#Override
public String getMoviePosterPath(int pos) {
return mInteractor.getMoviePosterPath(pos);
}
#Override
public int getSize() {
return mInteractor.getMovieSize();
}
}
Adapter
public class MovieListAdapter extends RecyclerView.Adapter<MovieListViewHolder> {
private MovieListPresenter mPresenter;
private Context ctx;
public MovieListAdapter(MovieListPresenter mPresenter, Context context) {
this.mPresenter = mPresenter;
this.ctx = context;
}
#Override
public MovieListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MovieListViewHolder(LayoutInflater.from(ctx).inflate(R.layout.main_view_movie_list, parent, false));
}
#Override
public void onBindViewHolder(MovieListViewHolder holder, int position) {
mPresenter.bindAtPosition(position, holder);
String image_url = IMAGE_URL_BASE_PATH + mPresenter.getMoviePosterPath(position);
Picasso.with(ctx).load(image_url).placeholder(android.R.drawable.sym_def_app_icon)
.error(android.R.drawable.sym_def_app_icon).into(holder.mImage);
}
#Override
public int getItemCount() {
return mPresenter.getSize();
}
}
MovieCall class
public class ServerMovieCall {
private Retrofit retrofit;
private static ServerMovieCall mInstance;
private Context ctx;
public static ServerMovieCall getInstance() {
if (mInstance == null) {
mInstance = new ServerMovieCall();
}
return mInstance;
}
public ServerMovieCall() {
configureClient();
}
private void configureClient() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(logging).addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url().newBuilder().addQueryParameter("api_key", Constants.API_KEY).build();
request = request.newBuilder().url(url).build();
return chain.proceed(request);
}
}).build();
retrofit = new Retrofit.Builder().baseUrl(Constants.API_BASE_URL).client(client)
.addConverterFactory(GsonConverterFactory.create()).build();
}
public void getMovieList(final IOnDataCallback<List<MovieListModel>> onDataCallback) {
IServerMovieApiHelper iMovieReviewApiService = retrofit.create(IServerMovieApiHelper.class);
Call<MovieListResponse> call = iMovieReviewApiService.getMovieList();
call.enqueue(new Callback<MovieListResponse>() {
#Override
public void onResponse(Call<MovieListResponse> call, Response<MovieListResponse> response) {
if (response.isSuccessful()) {
onDataCallback.onSuccess(response.body().getMovies());
} else {
onDataCallback.onFailure(response.message());
}
}
#Override
public void onFailure(Call<MovieListResponse> call, Throwable t) {
onDataCallback.onFailure(t.getLocalizedMessage());
}
});
}
Contract interfaces
public interface IMovieContarctor {
public interface MovieListInteractor {
List<MovieListModel> getMovieList();
MovieListModel getMovie(int pos);
String getMoviePosterPath(int pos);
}
public interface MovieListPresenter {
void bindAtPosition(int position, MovieListViewHolder holder);
String getMoviePosterPath(int pos);
int getSize();
void getData();
}
public interface MovieListView {
void onDataChange(List<MovieListModel> data, String message);
void onDataFailure(String message);
}
}
DataCallback Listener.
public interface IOnDataCallback<T> {
void onSuccess(T data);
void onFailure(String message);
}
In Interactor class:
#Override
public List<MovieListModel> getMovieList() {
if (mList == null)
mList = new ArrayList<>();
ServerMovieCall mCall = new ServerMovieCall();
mCall.getMovieList(new IOnDataCallback<List<MovieListModel>>() {
#Override
public void onSuccess(List<MovieListModel> data) {
mList.addAll(data);
mListener.onSuccess(mList, "Your message");
}
#Override
public void onFailure(String message) {
Log.d(TAG, "onFailure: " + message);
}
});
return mList;
}
In Presenter class:
#Override
public void onSuccess(List<MovieListModel> data, String msg) {
mList = data;
mView.onDataChange(data, msg);
}
Related
I'm stuck somewhere in between getting json array inside a object setting it to recylerview, I have to send a key to fetch data and getting response in json array inside a object. Didn't understand solutions got here, so I'm here if Somebody can help mre understand.
////Main class
public class today_doctors extends AppCompatActivity {
viewModel_doc listViewModel;
List<model_doc> datalist;
todayDoctorAdapter adapter;
TextView clinic_name;
RecyclerView recview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_today_doctors);
recview=findViewById(R.id.rv);
recview.setLayoutManager(new LinearLayoutManager(this));
recview.addItemDecoration(new DividerItemDecoration(this, 0));
adapter=new todayDoctorAdapter(datalist);
recview.setAdapter(adapter);
clinic_name=findViewById(R.id.tvDrName);
process();
}
public void process(){
listViewModel= new ViewModelProvider(this).get(viewModel_doc.class);
listViewModel.getDatalistObserver ().observe(this, new Observer<List<model_doc>>() {
#Override
public void onChanged(List<model_doc> Models) {
if(Models!=null) {
datalist= Models;
adapter.updateList(Models);
}
else
{
recview.setVisibility(View.GONE);
Toast.makeText(today_doctors.this, "No data recieved", Toast.LENGTH_SHORT).show();
}
}
});
listViewModel.makeApiCall();
}
//////////Viewmodel class
public class viewModel_doc extends ViewModel
{
private MutableLiveData<List<model_doc>> datalist2;
public viewModel_doc(){
datalist2=new MutableLiveData<>();
}
public MutableLiveData<List<model_doc>> getDatalistObserver()
{
return datalist2;
}
public void makeApiCall()
{
apiSet apiServices= apiController.getInstance().getApi();
Call<List<model_doc>> calldoc=apiServices.getList2("ll0004");
calldoc.enqueue(new Callback<List<model_doc>>() {
#Override
public void onResponse(Call<List<model_doc>> call, Response<List<model_doc>> response) {
datalist2.postValue(response.body());
}
#Override
public void onFailure(Call<List<model_doc>> call, Throwable t) {
datalist2.postValue(null);
Log.e("Error :",t.getMessage());
}
});
}
}
///////////////////main model
public class model_doc {
String status,msg;
ArrayList<Data> data;
public model_doc(String status, String msg, ArrayList<Data> data) {
this.status = status;
this.msg = msg;
this.data = data;
}
public String getStatus() {
return status;
}
public String getMsg() {
return msg;
}
public ArrayList<Data> getData() {
return data;
}
public static class Data {
String doctor_id;
String doctor_name;
String proposed_date;
String date;
// Getters setters
public Data(String doctor_id, String doctor_name, String proposed_date, String date) {
this.doctor_id = doctor_id;
this.doctor_name = doctor_name;
this.proposed_date = proposed_date;
this.date = date;
}
public String getDoctor_id() {
return doctor_id;
}
public String getDoctor_name() {
return doctor_name;
}
public String getProposed_date() {
return proposed_date;
}
public String getDate() {
return date;
}
}
}
////api interface
#FormUrlEncoded
#POST("doctor_list")
Call<List<model_doc>>getList2(
#Field("clinic_id") String clinic_id
);
//////////////////controller
public class apiController {
private static final String url="https://xyz.in/api/";
private static apiController clientObject;
private static Retrofit retrofit;
apiController()
{
retrofit=new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized apiController getInstance(){
if(clientObject==null)
clientObject=new apiController();
return clientObject;
}
public apiSet getApi(){
return retrofit.create(apiSet.class);
}
}
////////////recycler adapter, made some changes in main model for nested data could handle it to adapter
public class todayDoctorAdapter extends RecyclerView.Adapter<todayDoctorAdapter.viewholder>
{
List<model_doc> datalist2;
public todayDoctorAdapter(List<model_doc> list){
this.datalist2=list;}
public void updateList(List<model_doc>list){
this.datalist2=list;
notifyDataSetChanged();
}
#NonNull
#Override
public todayDoctorAdapter.viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType){
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_doctors,parent,false);
return new todayDoctorAdapter.viewholder(view);
}
#Override
public void onBindViewHolder(#NonNull todayDoctorAdapter.viewholder holder, int position){
holder.doctor_name.setText(String.format("Dr.%s", datalist2.get(position).getDoctor_app()));
holder.proposed_date.setText(String.format("Apt: %s","TODAY"));
String doc=datalist2.get(position).getDoctor_app();
holder.cv.setOnClickListener(
new View.OnClickListener(){
#Override
public void onClick(View arg0) {
Intent intent = new Intent(arg0.getContext(), PatientsUnderDoctor.class);
intent.putExtra("doc_name", doc);
arg0.getContext().startActivity(intent);
}
});
}
#Override
public int getItemCount(){
if (this.datalist2!=null){
return this.datalist2.size();
}
return 0;
}
public static class viewholder extends RecyclerView.ViewHolder{
TextView doctor_name,proposed_date;
CardView cv;
public viewholder(#NonNull View itemView) {
super(itemView);
doctor_name=itemView.findViewById(R.id.drName);
proposed_date=itemView.findViewById(R.id.apptDate);
cv=itemView.findViewById(R.id.cv_patient);
}
}
}
//////////////////json data look like this
{
"status": "success",
"msg": "Found",
"data": [
{
"doc_code": "jhjh0001",
"app_date": "2022-09-13",
"doc_name": "kjk",
"count": 1
}
]
}
I am using android jetpack's pagination library. I am able to get data till page 2 , but i cannot get data of further pages even though i am passing params.key in my api call from loadAfter() method in Datasource. I am simple not able to understand where the problem is.
Heres my DataSource:
public class ApprovedBillsDataSource extends PageKeyedDataSource<Integer, BillsModel.Bills> {
static int FIRST_PAGE = 1;
String sortOrder;
String searchParam;
EmptyHandler emptyHandler;
ApprovedBillsDataSource(String sortOrder, String searchParam, EmptyHandler emptyHandler) {
this.sortOrder = sortOrder;
this.searchParam = searchParam;
this.emptyHandler = emptyHandler;
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params, #NonNull final LoadInitialCallback<Integer, BillsModel.Bills> callback) {
RestClient.webServices().getCompletePartnerBills(FIRST_PAGE, 1, sortOrder, searchParam).enqueue(new Callback<ApiResponse<BillsModel>>() {
#Override
public void onResponse(Call<ApiResponse<BillsModel>> call, Response<ApiResponse<BillsModel>> response) {
if (response.code() == 200) {
callback.onResult(response.body().getData().getBills(), null, FIRST_PAGE + 1);
if (response.body().getData().getBills() == null || response.body().getData().getBills().size() == 0) {
emptyHandler.onListEmpty();
}
}
}
#Override
public void onFailure(Call<ApiResponse<BillsModel>> call, Throwable t) {
}
});
}
#Override
public void loadBefore(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, BillsModel.Bills> callback) {
}
#Override
public void loadAfter(#NonNull LoadParams<Integer> params, #NonNull final LoadCallback<Integer, BillsModel.Bills> callback) {
RestClient.webServices().getCompletePartnerBills(params.key, 1, sortOrder, searchParam).enqueue(new Callback<ApiResponse<BillsModel>>() {
#Override
public void onResponse(Call<ApiResponse<BillsModel>> call, Response<ApiResponse<BillsModel>> response) {
if (response.code() == 200) {
callback.onResult(response.body().getData().getBills(), null);
}
}
#Override
public void onFailure(Call<ApiResponse<BillsModel>> call, Throwable t) {
}
});
}
And here is my Adapter:
public class ApprovedBillsAdapter extends PagedListAdapter<BillsModel.Bills, ApprovedBillsAdapter.ItemViewHolder> {
Context context;
ApprovedBillsAdapter(Context context) {
super(DIFF_CALLBACK);
this.context = context;
}
#NonNull
#Override
public ApprovedBillsAdapter.ItemViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new ApprovedBillsAdapter.ItemViewHolder(LayoutInflater.from(context).inflate(R.layout.row_approved_bills, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull ApprovedBillsAdapter.ItemViewHolder holder, int i) {
try {
final BillsModel.Bills bill = getItem(i);
holder.tv_bill_id.setText(bill.getBillId());
Picasso.with(context).load(bill.getCustomer_image()).placeholder(R.drawable.ic_avatar).into(holder.ivUserImage);
holder.tvCustomerName.setText(bill.getCustomer_name());
holder.tvAmount.setText("Rs." + bill.getBillAmount());
holder.tvMobileNumber.setText(bill.getCustomer_mobile());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context, BillDetailsActivity.class);
intent.putExtra("id", bill.getId());
context.startActivity(intent);
}
});
holder.tvPendingSinceValue.setText(bill.getUpdated_at());
} catch (Exception e) {
}
}
private static DiffUtil.ItemCallback<BillsModel.Bills> DIFF_CALLBACK =
new DiffUtil.ItemCallback<BillsModel.Bills>() {
#Override
public boolean areItemsTheSame(BillsModel.Bills oldItem, BillsModel.Bills newItem) {
return oldItem.getBillId().equals(newItem.getBillId());
}
#Override
public boolean areContentsTheSame(BillsModel.Bills oldItem, BillsModel.Bills newItem) {
return oldItem.equals(newItem);
}
};
class ItemViewHolder extends RecyclerView.ViewHolder {
TextView tv_bill_id;
#BindView(R.id.iv_user_image)
ImageView ivUserImage;
#BindView(R.id.tv_customer_name)
TextView tvCustomerName;
#BindView(R.id.tv_mobile_number)
TextView tvMobileNumber;
#BindView(R.id.tv_bill_id)
TextView tvBillId;
#BindView(R.id.tv_amount)
TextView tvAmount;
#BindView(R.id.tv_pending_since_value)
TextView tvPendingSinceValue;
public ItemViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
tv_bill_id = itemView.findViewById(R.id.tv_bill_id);
}
}
}
It got solved, i needed to add
Integer key = params.key + 1;
callback.onResult(response.body().getData().getOffers(), key);
to my code. Incrementing params.key on every loadAfter call was the key. And then passing it to the onResult function as adjacent key.
What I want: I want to implement google paging library. Which loads some number of data (let's say first 10). And while you scroll up It makes API call and loads more data.
What's issue: It is loading all the data instead of some data (let's say first 10). I have used ViewModel & PageKeyedDataSource for that.
What I tried: Code is below
InProgressFragment.java
public class InProgressFragment extends BaseFragment implements SalesDashboardView {
#BindView(R.id.recyclerview_applicants_list)
RecyclerView applicantsListRecyclerView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_applicants, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
setupRecyclerView();
}
private void setupRecyclerView() {
ApplicantsDataAdapter2 adapter = new ApplicantsDataAdapter2();
applicantsListRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
applicantsListRecyclerView.setHasFixedSize(true);
applicantsListRecyclerView.setAdapter(adapter);
SearchLoansInput searchLoansInput = new SearchLoansInput();
searchLoansInput.setUserName(sessionManager.getMobileNumber());
adapter.submitList(salesDashboardViewModel.getLoanDetailOutput(searchLoansInput));
}
}
SalesDashboardViewModel.java
public class SalesDashboardViewModel extends ViewModel {
private static final String TAG = SalesDashboardViewModel.class.getSimpleName();
private int DEFAULT_PER_PAGE = 3;
private MainThreadExecutor executor;
private SalesLoginInquiryUseCase mSalesInquiryUseCase;
#Inject
public SalesDashboardViewModel(SalesLoginInquiryUseCase salesLoginInquiryUseCase) {
mSalesInquiryUseCase = salesLoginInquiryUseCase;
}
public PagedList<LoanDetailOutput> getLoanDetailOutput(SearchLoansInput searchLoansInput) {
executor = new MainThreadExecutor();
SearchDataSource dataSource = new SearchDataSource(searchLoansInput, mSalesInquiryUseCase);
PagedList.Config config = new PagedList.Config.Builder()
.setPageSize(DEFAULT_PER_PAGE)
.setInitialLoadSizeHint(DEFAULT_PER_PAGE * 2)
.setEnablePlaceholders(true)
.build();
PagedList<LoanDetailOutput> loanDetailOutputPagedList =
new PagedList.Builder<>(dataSource, config)
.setFetchExecutor(executor)
.setNotifyExecutor(executor)
.build();
return loanDetailOutputPagedList;
}
}
SearchDataSource.java
public class SearchDataSource extends PageKeyedDataSource<Integer, LoanDetailOutput> {
private static final String TAG = SearchDataSource.class.getSimpleName();
private SearchLoansInput searchLoansInput;
private SalesLoginInquiryUseCase mSalesInquiryUseCase;
public SearchDataSource(SearchLoansInput searchLoansInput, SalesLoginInquiryUseCase mSalesInquiryUseCase) {
this.searchLoansInput = searchLoansInput;
this.mSalesInquiryUseCase = mSalesInquiryUseCase;
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params,
#NonNull LoadInitialCallback<Integer, LoanDetailOutput> callback) {
Log.e("mk", "loadInitial, requestedLoadSize: " + params.requestedLoadSize);
final int page = 1;
mSalesInquiryUseCase.setSalesLoginInquiryBody(searchLoansInput);
mSalesInquiryUseCase.execute()
.subscribe(new DisposableObserver<SearchLoansOutput>() {
#Override
public void onNext(SearchLoansOutput value) {
callback.onResult(
value.getLoanDetailList(),
0,
value.getCountLA(),
null,
page + 1);
Log.e("mk", "loadInitial, List Size: " + value.getLoanDetailList().size());
Log.e("mk", "loadInitial, TotalCount: " + value.getCountLA());
}
#Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
#Override
public void onComplete() {
}
});
}
#Override
public void loadBefore(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, LoanDetailOutput> callback) {
}
#Override
public void loadAfter(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, LoanDetailOutput> callback) {
Log.e("mk", "loadAfter, requestedLoadSize: " + params.requestedLoadSize);
final int page = params.key;
mSalesInquiryUseCase.setSalesLoginInquiryBody(searchLoansInput);
mSalesInquiryUseCase.execute()
.subscribe(new DisposableObserver<SearchLoansOutput>() {
#Override
public void onNext(SearchLoansOutput value) {
callback.onResult(
value.getLoanDetailList(),
page + 1);
Log.e("mk", "loadAfter, List Size: " + value.getLoanDetailList().size());
}
#Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
#Override
public void onComplete() {
}
});
}
}
ApplicantsDataAdapter2.java
public class ApplicantsDataAdapter2 extends PagedListAdapter<LoanDetailOutput, ApplicantsDataAdapter2.ApplicantsViewHolder> {
public ApplicantsDataAdapter2() {
super(DIFF_CALLBACK);
}
#Override
public ApplicantsDataAdapter2.ApplicantsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_applicant, parent, false);
return new ApplicantsDataAdapter2.ApplicantsViewHolder(itemView);
}
#Override
public void onBindViewHolder(ApplicantsDataAdapter2.ApplicantsViewHolder holder, int position) {
holder.bindView(getItem(position));
}
public class ApplicantsViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.tv_item_applicant_name)
TextView mApplicantNameTextView;
#BindView(R.id.tv_item_applicant_status)
TextView mApplicantStatusTextView;
#BindView(R.id.tv_item_applicant_creation_date)
TextView mApplicantDateCreationTextView;
ApplicantsViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
void bindView(LoanDetailOutput loanDetailOutput) {
if (loanDetailOutput != null) {
mApplicantNameTextView.setText(loanDetailOutput.getFirstName());
mApplicantStatusTextView.setText(loanDetailOutput.getStatus().getDisplayName());
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy");
String createdDate = null;
if (loanDetailOutput.getCreatedDate() != null) {
createdDate = String.valueOf(sdf.format(loanDetailOutput.getCreatedDate()));
}
mApplicantDateCreationTextView.setText(createdDate);
} else {
mApplicantNameTextView.setText("Loading...");
mApplicantStatusTextView.setText("Loading...");
mApplicantDateCreationTextView.setText("Loading...");
}
}
}
private static DiffUtil.ItemCallback<LoanDetailOutput> DIFF_CALLBACK = new DiffUtil.ItemCallback<LoanDetailOutput>() {
#Override
public boolean areItemsTheSame(LoanDetailOutput oldItem, LoanDetailOutput newItem) {
return oldItem.getId() == newItem.getId();
}
#Override
public boolean areContentsTheSame(LoanDetailOutput oldItem, LoanDetailOutput newItem) {
return true;
}
};
}
The main problem is method loadAfter of SearchDataSource class is never invoked.
Any help will be appreciated.
Edit: Added screenshot of logcat. It might be helpful.
I am trying to load data into my recyclerview via url okhttp calls, and I am receiving the following error:
"java.lang.ClassCastException: SearchActivity cannot be cast to SearchForBarbershop$BarbershopRequesterResponse"
Here are the classes.
SearchActivity:
public class SearchActivity extends AppCompatActivity {
private RecyclerAdapter mAdapter;
private RecyclerView mRecyclerView;
private LinearLayoutManager mLinearLayoutManager;
private ArrayList<Barbershop> barbershopList;
private SearchForBarbershop searchForBarbershop;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mLinearLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLinearLayoutManager);
barbershopList = new ArrayList<>();
mAdapter = new RecyclerAdapter(barbershopList);
mRecyclerView.setAdapter(mAdapter);
setRecyclerViewScrollListener();
searchForBarbershop = new SearchForBarbershop(this);
}
#Override
protected void onStart() {
super.onStart();
if (barbershopList.size() == 0) {
requestShop();
}
}
private int getLastVisibleItemPosition() {
return mLinearLayoutManager.findLastVisibleItemPosition();
}
private void setRecyclerViewScrollListener() {
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
int totalItemCount = mRecyclerView.getLayoutManager().getItemCount();
if (!searchForBarbershop.isLoadingData() && totalItemCount == getLastVisibleItemPosition() + 1) {
requestShop();
}
}
});
}
private void requestShop() {
try {
searchForBarbershop.getBarbershop();
} catch (IOException e) {
e.printStackTrace();
}
}
//#Override
public void receivedNewShop(final Barbershop newBarbershop) {
runOnUiThread(new Runnable() {
#Override
public void run() {
barbershopList.add(newBarbershop);
mAdapter.notifyItemInserted(barbershopList.size());
}
});
}
}
SearchForBarbershop:
public class SearchForBarbershop {
public interface BarbershopRequesterResponse {
void receivedNewBarbershop(Barbershop barbershop);
}
private BarbershopRequesterResponse barbershopRequesterResponse;
private OkHttpClient client;
private boolean isLoadingData;
public boolean isLoadingData() { return isLoadingData; }
public SearchForBarbershop (Activity listeningActivity) {
client = new OkHttpClient();
isLoadingData = false;
barbershopRequesterResponse = (BarbershopRequesterResponse) listeningActivity;
}
public void getBarbershop() throws IOException {
String url = "http://pubapi.yp.com/search-api/search/devapi/search?searchloc=30043&term=barbers&format=json&sort=distance&radius=50&listingcount=20&key=gmj3x7mhsh";
Request request = new Request.Builder().url(url).build();
isLoadingData = true;
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
isLoadingData = false;
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
JSONObject object = new JSONObject(response.body().string());
Barbershop receivedShop = new Barbershop(object);
barbershopRequesterResponse.receivedNewBarbershop(receivedShop);
isLoadingData = false;
} catch (JSONException e) {
isLoadingData = false;
e.printStackTrace();
}
}
});
}
}
Barbershop:
public class Barbershop{
private String name;
private String city;
public Barbershop(JSONObject barbershopJSON) {
try {
JSONArray businessArray = barbershopJSON.getJSONObject("searchResult").getJSONObject("searchListings").getJSONArray("searchListing");
for(int i = 0; i < businessArray.length(); i++) {
//Parse JSON and assign to variables
JSONObject business_object_1 = businessArray.getJSONObject(i);
String primaryc = business_object_1.getString("primaryCategory");
//Check to make sure the main category is "Barbers"
if((primaryc).equals("Barbers")) {
name = business_object_1.getString("businessName");
city = business_object_1.getString("city");
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public String getCity() {
return city;
}
public String getName() {
return name;
}
}
RecyclerAdapter:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ShopHolder> {
private ArrayList<Barbershop> mbarbershops;
public RecyclerAdapter(ArrayList<Barbershop> barbershops) {
mbarbershops = barbershops;
}
#Override
public RecyclerAdapter.ShopHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View inflatedView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cardview_barber_search, parent, false);
return new ShopHolder(inflatedView);
}
#Override
public void onBindViewHolder(RecyclerAdapter.ShopHolder holder, int position) {
Barbershop itemBarbershop = mbarbershops.get(position);
holder.bindShop(itemBarbershop);
}
#Override
public int getItemCount() {
return 0;
}
public static class ShopHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mName;
private TextView mCity;
public ShopHolder(View view) {
super(view);
mName = (TextView) view.findViewById(R.id.textViewName);
mCity = (TextView) view.findViewById(R.id.textViewCity);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
public void bindShop(Barbershop barbershop) {
mName.setText(barbershop.getName());
mCity.setText(barbershop.getCity());
}
}
}
It can't be cast because it doesn't implement that interface. Your commented-out #override statement should be a clue for you here.
Change it to:
public class SearchActivity extends AppCompatActivity
implements SearchForBarbershop.BarbershopRequesterResponse {
....
And don't forget to remove the comment for method you implemented:
#Override
public void receivedNewShop(final Barbershop newBarbershop) {
....
I think you need change constructor SearchForBarbershop
BarbershopRequesterResponse listener;
Context context
public SearchForBarbershop (Context context,BarbershopRequesterResponse listener) {
client = new OkHttpClient();
isLoadingData = false;
this.context = context;
this.listener = listener;
}
And change in SearchActivity
searchForBarbershop = new SearchForBarbershop(SearchActivity.this, this);
I can normally get and show data on Toast message, but I cannot add them to RecyclerView. How can I do this? Please help me. Thanks. I am sharing my code below.
NewsCatalog.java
public class NewsCatalog {
public List<MainNodes> nodes;
}
MainNodes.java
public class MainNodes {
public SubNodes node;
}
SubNodes.java
public class SubNodes {
public String body;
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
NewsInterface
public interface NewsService {
String BASE_URL = "http://test.muhabirce.de/app/term/";
#GET("saglik")
Call<NewsCatalog> newsCatalog();
}
Adapter.java
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private ArrayList<SubNodes> subNodes;
private Context context;
public NewsAdapter(ArrayList<SubNodes> subNodes, Context context) {
this.subNodes = subNodes;
this.context = context;
}
#Override
public NewsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context)
.inflate(R.layout.card_view_items, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(NewsAdapter.ViewHolder holder, int position) {
holder.tvText.setText(subNodes.get(position).getBody());
}
#Override
public int getItemCount() {
return subNodes.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView tvText;
public ViewHolder(View itemView) {
super(itemView);
tvText = (TextView) itemView.findViewById(R.id.tvText);
}
}
}
MainActivity.java
private void bindDatas() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(NewsService.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
NewsService newsService = retrofit.create(NewsService.class);
Call<NewsCatalog> requestCatalog = newsService.newsCatalog();
requestCatalog.enqueue(new Callback<NewsCatalog>() {
#Override
public void onResponse(Call<NewsCatalog> call, Response<NewsCatalog> response) {
SubNodes subNodess = new SubNodes();
if (!response.isSuccessful()) {
Log.i("TAG", "Error: " + response.code());
} else {
NewsCatalog catalog = response.body();
try {
for (MainNodes m : catalog.nodes
) {
subNodess.setBody(m.node.body);
}
} catch (Exception e) {
Log.i(TAG, "" + e.getMessage());
}
}
subNodes.add(subNodess);
adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<NewsCatalog> call, Throwable t) {
Log.e(TAG, "Error: " + t.getMessage());
}
});
}
}
You should not create a new Subnodes object in response callback. Adapter does not have reference to this object and so the changes in data is not reflected. Update the subnodes object in the recyclerview adapter. Then only notifyDataSetChanged() will reflect the change in data.