I want to build a movie app that consumes a REST api using retrofit and displays images using Picasso and bring in Retrofit and show real movie posters as well as detail information for each movie.
i'm using The Movie Database Api to get some real data into our app. Checkout their documentation and get familiar with their API, specially the movies/popular endpoint
But when running the application white screen showing pictures does not show movies and I do not know where is the problem
this MainActivity :
package com.walkatheri.movies;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.List;
import retrofit.Callback;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
RecyclerView mRecyclerView;
final MoviesAdapter mAdapter;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
mAdapter = new MoviesAdapter(this);
mRecyclerView.setAdapter(mAdapter);
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://api.themoviedb.org/3")
.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addEncodedQueryParam("api_key", "MY _KEY");
}
})
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
MoviesApiService service = restAdapter.create(MoviesApiService.class);
service.getPopularMovies(new Callback<Movies.MovieResult>() {
#Override
public void success(Movies.MovieResult movieResult, Response response) {
mAdapter.setMovieList(movieResult.getResults());
}
#Override
public void failure(RetrofitError error) {
error.printStackTrace();
}
});
}
public static class MovieViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public MovieViewHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.imageView);
}
}
public static class MoviesAdapter extends RecyclerView.Adapter<MovieViewHolder> {
List<Movies>MovieList ;
private LayoutInflater mInflater;
private Context mContext;
public MoviesAdapter(Context context)
{
this.mContext = context;
this.mInflater = LayoutInflater.from(context);
this.MovieList = new ArrayList<>();
}
public void setMovieList(List<Movies> movieList)
{
this.MovieList=movieList ;
// The adapter needs to know that the data has changed. If we don't call this, app will crash.
notifyDataSetChanged();
}
#Override
public MovieViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.row_movie, parent, false);
MovieViewHolder viewHolder = new MovieViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(MovieViewHolder holder, int position) {
Movies movies = MovieList.get(position);
Picasso.with(mContext)
.load(movies.getPoster()).placeholder(R.color.colorAccent)
.into(holder.imageView);
}
#Override
public int getItemCount() {
return (MovieList == null) ? 0 : MovieList.size();
}
}
}
Movies class :
package com.walkatheri.movies;
import android.graphics.Movie;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Created by waad on 08/10/2016.
*/
public class Movies {
private String title;
#SerializedName("poster_path")
private String poster;
#SerializedName("overview")
private String description;
#SerializedName("backdrop_path")
private String backdrop;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPoster() {
return "http://image.tmdb.org/t/p/w500" + poster;
}
// public String getPoster() {
// return "http://t2.gstatic.com/images?q=tbn:ANd9GcQW3LbpT94mtUG1PZIIzJNxmFX399wr_NcvoppJ82k7z99Hx6in";
// }
public void setPoster(String poster) {
this.poster = poster;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getBackdrop() {
return backdrop;
}
public void setBackdrop(String backdrop) {
this.backdrop = backdrop;
}
public static class MovieResult {
private List<Movies> resulte;
public List<Movies> getResults() {
return resulte;
}
}}
MoviesApiService class:
package com.walkatheri.movies;
import retrofit.Callback;
import retrofit.http.GET;
/**
* Created by waad on 18/10/2016.
*/
public interface MoviesApiService {
#GET("/movie/popular")
void getPopularMovies(Callback<Movies.MovieResult>cb);
}
Very difficult to point out mistakes without any hint like stacktraces.
Some pointers
Use retrofit asynchronous call.
You need .addConverterFactory(GsonConverterFactory.create()) to convert json to pojos.
Image will be loaded only if you us the url http://image.tmdb.org/t/p/w185"+"yourposterpath". Check the moviedb link
Update your libs and change your api accordingly (Recommended)
Lastly a clean architecture will help you write tests properly. Your code is unstructured and you need to separate components properly. Suggest you read about MVP or MVVM patterns. Dagger can also help.
A good read about retrofit https://inthecheesefactory.com/blog/retrofit-2.0/en
So the changes
public class TestActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private MoviesAdapter mAdapter;
public static final String MOVIE_DB_API_URL = "http://api.themoviedb.org/3/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
mAdapter = new MoviesAdapter(this);
mRecyclerView.setAdapter(mAdapter);
final OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15,TimeUnit.SECONDS)
.build();
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(MOVIE_DB_API_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
MoviesApiService service = restAdapter.create(MoviesApiService.class);
Call<MoviesList> movieResultCallback = service.getPopularMovies();
// asynchronous call
movieResultCallback.enqueue(new Callback<MoviesList>() {
#Override
public void onResponse(Call<MoviesList> call, Response<MoviesList> response) {
//int code = response.code();
// can check the status code
mAdapter.setMovieList(response.body().getResults());
}
#Override
public void onFailure(Call<MoviesList> call, Throwable t) {
}
});
}
public static class MovieViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public MovieViewHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.image);
}
}
public static class MoviesAdapter extends RecyclerView.Adapter<MovieViewHolder> {
List<Movies>MovieList ;
private LayoutInflater mInflater;
private Context mContext;
public MoviesAdapter(Context context)
{
this.mContext = context;
this.mInflater = LayoutInflater.from(context);
this.MovieList = new ArrayList<>();
}
public void setMovieList(List<Movies> movieList)
{
this.MovieList=movieList ;
// The adapter needs to know that the data has changed. If we don't call this, app will crash.
notifyDataSetChanged();
}
#Override
public MovieViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.row, parent, false);
MovieViewHolder viewHolder = new MovieViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(MovieViewHolder holder, int position) {
Movies movies = MovieList.get(position);
Picasso.with(mContext)
.load("http://image.tmdb.org/t/p/w185"+movies.getPoster_path()).placeholder(R.color.colorAccent)
.into(holder.imageView);
}
#Override
public int getItemCount() {
return (MovieList == null) ? 0 : MovieList.size();
}
}
public static class LoggingInterceptor implements Interceptor {
#Override public okhttp3.Response intercept(Chain chain) throws IOException {
HttpUrl url = chain.request().url()
.newBuilder()
.addQueryParameter("api_key", "4848b32592990671646565fa3240a7bc")
.build();
Request request = chain.request().newBuilder().url(url).build();;
long t1 = System.nanoTime();
String requestLog = String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers());
//YLog.d(String.format("Sending request %s on %s%n%s",
// request.url(), chain.connection(), request.headers()));
if(request.method().compareToIgnoreCase("post")==0){
requestLog ="\n"+requestLog+"\n"+bodyToString(request);
}
Log.d("TAG","request"+"\n"+requestLog);
okhttp3.Response response = chain.proceed(request);
long t2 = System.nanoTime();
String responseLog = String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers());
String bodyString = response.body().string();
Log.d("TAG","response"+"\n"+responseLog+"\n"+bodyString);
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), bodyString))
.build();
//return response;
}
}
private static String bodyToString(final Request request) {
try {
final Request copy = request.newBuilder().build();
final Buffer buffer = new Buffer();
if (copy != null && copy.body() != null) // make sure its not null to avoif NPE
copy.body().writeTo(buffer);
return buffer.readUtf8();
} catch (final IOException e) {
return "did not work";
}
}
}
Then
public interface MoviesApiService {
#GET("movie/popular")
Call<MoviesList> getPopularMovies();
}
My Model classes
Use http://www.jsonschema2pojo.org/ to convert json to pojo
I copied the below for one the respositories on github.
Lots of similar repositories avaiable on github. https://github.com/ewintory/udacity-popular-movies and many more..
public class Movies implements Parcelable {
private int id,vote_count,favourite,reviewsaved,trailersaved;
private float vote_average,popularity;
private String original_language,original_title,overview,release_date,poster_path,title,generids,backdrop_path;
private boolean video,favored;
public Movies()
{
}
public void setReviewsaved(int reviewsaved) {
this.reviewsaved = reviewsaved;
}
public void setTrailersaved(int trailersaved) {
this.trailersaved = trailersaved;
}
public int getTrailersaved() {
return trailersaved;
}
public int getReviewsaved() {
return reviewsaved;
}
public void setFavored(boolean favored) {
this.favored = favored;
}
public void setId(int id) {
this.id = id;
}
public void setVote_count(int vote_count) {
this.vote_count = vote_count;
}
public void setFavourite(int favourite) {
this.favourite = favourite;
}
public void setVote_average(float vote_average) {
this.vote_average = vote_average;
}
public void setOriginal_language(String original_language) {
this.original_language = original_language;
}
public void setOriginal_title(String original_title) {
this.original_title = original_title;
}
public void setOverview(String overview) {
this.overview = overview;
}
public void setRelease_date(String release_date) {
this.release_date = release_date;
}
public void setPoster_path(String poster_path) {
this.poster_path = poster_path;
}
public void setPopularity(float popularity) {
this.popularity = popularity;
}
public void setTitle(String title) {
this.title = title;
}
public void setGenerids(String generids) {
this.generids = generids;
}
public void setbackdrop_path(String backdrop_path) {
this.backdrop_path = backdrop_path;
}
public void setVideo(boolean video) {
this.video = video;
}
public String getGenerids() {
return generids;
}
public int getId() {
return id;
}
public int getVote_count() {
return vote_count;
}
public float getVote_avarage() {
return vote_average;
}
public String getOriginal_language() {
return original_language;
}
public String getOriginal_title() {
return original_title;
}
public String getOverview() {
return overview;
}
public String getRelease_date() {
return release_date;
}
public String getBackdrop_path() {
return backdrop_path;
}
public int getFavourtite() {
return favourite;
}
public String getPoster_path() {
return poster_path;
}
public float getPopularity() {
return popularity;
}
public String getTitle() {
return title;
}
public boolean isVideo() {
return video;
}
// Parcelling part
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.original_language);
dest.writeString(this.original_title);
dest.writeString(this.overview);
dest.writeString(this.poster_path);
dest.writeString(this.generids);
dest.writeString(this.title);
dest.writeString(this.release_date);
dest.writeString(this.backdrop_path);
dest.writeInt(this.favourite);
dest.writeInt(this.id);
dest.writeInt(this.vote_count);
dest.writeFloat(this.vote_average);
dest.writeFloat(this.popularity);
}
protected Movies(Parcel in) {
this.original_language = in.readString();
this.original_title = in.readString();
this.overview = in.readString();
this.poster_path = in.readString();
this.generids = in.readString();
this.title = in.readString();
this.release_date = in.readString();
this.backdrop_path = in.readString();
this.favourite = in.readInt();
this.id = in.readInt();
this.vote_count = in.readInt();
this.vote_average =in.readFloat();
this.popularity = in.readFloat();
}
public static final Creator<Movies> CREATOR = new Creator<Movies>() {
public Movies createFromParcel(Parcel source) {
return new Movies(source);
}
public Movies[] newArray(int size) {
return new Movies[size];
}
};
#Override
public int describeContents() {
return 0;
}
}
MoviesList
public class MoviesList {
private int total_pages;
public int getTotal_pages() {
return total_pages;
}
private ArrayList<Movies> results;
public ArrayList<Movies> getResults() {
return results;
}
}
Finally updated libs
// Okhttp
compile 'com.squareup.okhttp3:okhttp:3.4.1'
//Retrofit and adapters
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.picasso:picasso:2.5.2'
You can check your logs
It's almost impossible to know for sure what's going on, given your vague input, but my bet would be that you haven't specified internet permission in app's manifest:
<uses-permission android:name="android.permission.INTERNET"/>
(in src/main/AndroidManifest.xml, under manifest tag)
Related
I am using Android Paging with Room Database.I am going to fetch data using retrofit.But I am getting error No adapter attached; skipping layout.I searched a lot but dont find solution for this. Base url is working, for security reason i just hide base url.
private StoreAdapter storeAdapter;
private Store_ViewModel store_viewModel;
private RecyclerView recyclerView;
private static final String URL_DATA="https://xxxx/";
//insertion
private Store_Repository store_repository;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
store_repository=new Store_Repository(getApplication());
//adapter
storeAdapter=new StoreAdapter(getApplicationContext(), this);
//recycler
recyclerView=findViewById(R.id.recycler_store);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
store_viewModel=new ViewModelProvider(this).get(Store_ViewModel.class);
store_viewModel.pagedListLiveData.observe(this, new Observer<PagedList<StoreModel>>() {
#Override
public void onChanged(PagedList<StoreModel> storeModels) {
storeAdapter.submitList(storeModels);
recyclerView.setAdapter(storeAdapter);
}
});
getAllProducts();
}
private void getAllProducts() {
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(URL_DATA)
.addConverterFactory(GsonConverterFactory.create())
.build();
//calling api
Api api=retrofit.create(Api.class);
Call<List<StoreModel>>call=api.getAllProducts();
call.enqueue(new Callback<List<StoreModel>>() {
#Override
public void onResponse(Call<List<StoreModel>> call, Response<List<StoreModel>> response) {
if (response.isSuccessful())
{
store_repository.insert(response.body());
}
}
#Override
public void onFailure(Call<List<StoreModel>> call, Throwable t) {
Toast.makeText(MainActivity.this, "Something get Wrong", Toast.LENGTH_SHORT).show();
}
});
}
This is my ViewModel Class
public class Store_ViewModel extends AndroidViewModel {
public LiveData<PagedList<StoreModel>>pagedListLiveData;
private StoreDao storeDao;
public Store_ViewModel(#NonNull Application application) {
super(application);
storeDao= StoreDatabase.getINSTANCE(application).storeDao();
pagedListLiveData=new LivePagedListBuilder<>(
storeDao.getAllItems(),5
).build();
}
}
And this is my adapter class
public class StoreAdapter extends PagedListAdapter<StoreModel,StoreAdapter.StoreViewHolder> {
private Context context;
private static Listener listener;
public StoreAdapter(Context context,Listener listener)
{
super(storeModelItemCallback);
this.context=context;
this.listener=listener;
}
#NonNull
#Override
public StoreViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return null;
}
#Override
public void onBindViewHolder(#NonNull StoreViewHolder holder, int position) {
StoreModel storeModel=getItem(position);
holder.Product_name.setText(storeModel.getProduct_name());
holder.Product_weight.setText(storeModel.getProduct_weight());
holder.Price.setText(storeModel.getPrice());
holder.Mrp.setText(storeModel.getMrp());
}
static class StoreViewHolder extends RecyclerView.ViewHolder
{
TextView Product_name;
TextView Product_weight;
TextView Price;
TextView Mrp;
public StoreViewHolder(#NonNull View itemView) {
super(itemView);
Product_name=itemView.findViewById(R.id.product_name);
Product_weight=itemView.findViewById(R.id.product_weight);
Price=itemView.findViewById(R.id.price);
Mrp=itemView.findViewById(R.id.mrp);
//listener
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemCLickListener(getAdapterPosition());
}
});
}
}
static DiffUtil.ItemCallback<StoreModel> storeModelItemCallback=new DiffUtil.ItemCallback<StoreModel>() {
#Override
public boolean areItemsTheSame(#NonNull StoreModel oldItem, #NonNull StoreModel newItem) {
return oldItem.getDatabase_id()==newItem.getDatabase_id();
}
#SuppressLint("DiffUtilEquals")
#Override
public boolean areContentsTheSame(#NonNull StoreModel oldItem, #NonNull StoreModel newItem) {
return oldItem.equals(newItem);
}
};
Json Response from Server
{"status":1,"msg":"",
"paginate":{"limit":1000,"PageNo":1},
"data":
[
{
"product_id":23234,
"product_brand_id":130,
"product_name":"Xyz"
,"product_code":"1554729666482",
"mrp":5,
"price":4,
"product_weight":1,
"product_weight_unit":"PCS"
}
,{"product_id":23244,
"product_brand_id":130,
"product_name":"Abc - 100 Gms",
"product_code":"9A","mrp":38,"price":31.94,
"product_weight":100,"product_weight_unit":"GM"}
ApiInterface
public interface Api {
#GET("/get-products")
Call<List<StoreModel>>getAllProducts();
}
Below is my StoreModel in which i am using room database fro creating tables
#Entity(tableName = "store",indices = #Index(value="product_id",unique = true))
public class StoreModel {
#PrimaryKey(autoGenerate = true)
private int database_id;
#SerializedName("product_id")
private int product_id;
#SerializedName("product_brand_id")
private int product_brand_id;
#SerializedName("product_name")
private String product_name;
#SerializedName("product_code")
private int product_code;
#SerializedName("mrp")
private int mrp;
#SerializedName("price")
private int price;
#SerializedName("product_weight")
private int product_weight;
#SerializedName("product_weight_unit")
private String product_weight_unit;
public StoreModel() {
}
public StoreModel(int product_id, int product_brand_id, String product_name, int product_code, int mrp, int price, int product_weight, String product_weight_unit) {
this.product_id = product_id;
this.product_brand_id = product_brand_id;
this.product_name = product_name;
this.product_code = product_code;
this.mrp = mrp;
this.price = price;
this.product_weight = product_weight;
this.product_weight_unit = product_weight_unit;
}
public int getProduct_id() {
return product_id;
}
public void setProduct_id(int product_id) {
this.product_id = product_id;
}
public int getProduct_brand_id() {
return product_brand_id;
}
public void setProduct_brand_id(int product_brand_id) {
this.product_brand_id = product_brand_id;
}
public String getProduct_name() {
return product_name;
}
public void setProduct_name(String product_name) {
this.product_name = product_name;
}
public int getProduct_code() {
return product_code;
}
public void setProduct_code(int product_code) {
this.product_code = product_code;
}
public int getMrp() {
return mrp;
}
public void setMrp(int mrp) {
this.mrp = mrp;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getProduct_weight() {
return product_weight;
}
public void setProduct_weight(int product_weight) {
this.product_weight = product_weight;
}
public String getProduct_weight_unit() {
return product_weight_unit;
}
public void setProduct_weight_unit(String product_weight_unit) {
this.product_weight_unit = product_weight_unit;
}
public int getDatabase_id() {
return database_id;
}
public void setDatabase_id(int database_id) {
this.database_id = database_id;
}
}
Below is Dao class
#Dao
public interface StoreDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(List<StoreModel> storeModels);
#Query("DELETE FROM store")
void deleteAll();
#Query("SELECT * FROM store ORDER BY database_id ASC")
DataSource.Factory<Integer,StoreModel>getAllItems();
}
Set recyclerView.setAdapter(storeAdapter); outside of observer because each time data is observed it will set adapter. So, adapter is attached to recyclerView only once. Like
recyclerView.setAdapter(storeAdapter);
store_viewModel.pagedListLiveData.observe(this, new Observer<PagedList<StoreModel>>() {
#Override
public void onChanged(PagedList<StoreModel> storeModels) {
storeAdapter.submitList(storeModels);
//recyclerView.setAdapter(storeAdapter);
}
});
From the API you are not getting exactly the StoreModel as response. You are getting another object which is StoreModel is a child object. You have to create resposne object like below:
public class ResponseObject{
//#SerializedName("status")
//private int status;
#SerializedName("data")
private List<StoreModel> storeModelList;
//getters and setters goes here
}
And then your interface should be like below as you are expecting
ResponseObject here
public interface Api {
#GET("/get-products")
Call<ResponseObject> getAllProducts();
}
Those are categories and subcategories. There can be subcategory or not.
JsonCode to be used is as below.
categoryId is what will change to call subcategories.
E.g. If you want to see subcategories of cars
Json Code
[{"Id":1,"TitleEN":"Cars","TitleAR":"سيارات","Photo":"http://souq.hardtask.co//Files/CategoryPhotos/ce686544-9f51-4213-b5db-7c015b788e8d.png","ProductCount":"3","HaveModel":"0","SubCategories":[{"Id":6,"TitleEN":"Cat6","TitleAR":"قسم6","Photo":"http://souq.hardtask.co//Files/CategoryPhotos/ce686544-9f51-4213-b5db-7c015b788e8d.png","ProductCount":"3","HaveModel":"0","SubCategories":[]}]},{"Id":2,"TitleEN":"Cat2","TitleAR":"قسم2","Photo":"http://souq.hardtask.co//Images/no_image.png","ProductCount":"8","HaveModel":"0","SubCategories":[{"Id":13,"TitleEN":"cat1 -1 ","TitleAR":"cat1 - 1","Photo":"http://souq.hardtask.co//Images/no_image.png","ProductCount":"8","HaveModel":"0","SubCategories":[]}]},{"Id":3,"TitleEN":"Cat3","TitleAR":"قسم3","Photo":"http://souq.hardtask.co//Images/no_image.png","ProductCount":"2","HaveModel":"0","SubCategories":[]},{"Id":4,"TitleEN":"Cat4","TitleAR":"قسم4","Photo":"http://souq.hardtask.co//Images/no_image.png","ProductCount":"1","HaveModel":"0","SubCategories":[]},{"Id":5,"TitleEN":"Cat5","TitleAR":"قسم5","Photo":"http://souq.hardtask.co//Images/no_image.png","ProductCount":"0","HaveModel":"0","SubCategories":[]},{"Id":8,"TitleEN":"Cat8","TitleAR":"قسم8","Photo":"http://souq.hardtask.co//Images/no_image.png","ProductCount":"0","HaveModel":"0","SubCategories":[]},{"Id":9,"TitleEN":"Slide01","TitleAR":"Slide02","Photo":"http://souq.hardtask.co//Files/CategoryPhotos/2ba07cb2-49a0-47e4-aba6-ef10a916fb12.png","ProductCount":"0","HaveModel":"0","SubCategories":[]}]
ImageAdapter
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c){
mContext = c;
}
#Override
public int getCount(){
return images.size();
}
#Override
public Object getItem(int position){
return images.get(position);
}
public long getItemId(int position){
return 0;
}
public View getView(int position, View convertView, ViewGroup parent){
ImageView imageview;
if (convertView == null){
imageview = new ImageView(mContext);
imageview.setPadding(0, 0, 0, 0);
//imageview.setLayoutParams(new GridLayout.MarginLayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
imageview.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageview.setAdjustViewBounds(true);
} else {
imageview = (ImageView) convertView;
}
Picasso.with(mContext).load(images.get(position)).placeholder(R.mipmap.ic_launcher).into(imageview);
return imageview;
}
/*
Custom methods
*/
public void addItem(String url){
images.add(url);
}
public void clearItems() {
images.clear();
}
public ArrayList<String> images = new ArrayList<String>();
}
Movie Model
public class Movie implements Parcelable {
public String TitleEN;
public String TitleAR;
public String Photo;
public int id;
public Movie(){
}
protected Movie(Parcel in) {
TitleEN = in.readString();
TitleAR = in.readString();
Photo = in.readString();
id = in.readInt();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(TitleEN);
dest.writeString(TitleAR);
dest.writeString(Photo);
dest.writeInt(id);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Movie> CREATOR = new Parcelable.Creator<Movie>() {
#Override
public Movie createFromParcel(Parcel in) {
return new Movie(in);
}
#Override
public Movie[] newArray(int size) {
return new Movie[size];
}
};
}
Fragament_main
public class Fragament_main extends Fragment {
public View mainFragmentView;
public String LOG_TAG = "ShowcaseFragment";
public ArrayList<Movie> movies = new ArrayList<Movie>();
private RequestQueue mRequestQueue;
public ImageAdapter imageAdapter;
public static Fragament_main instance;
GridView gridview;
public boolean isDualPane = false;
// static to preserve sorting over orientation changes (activity restart)
public static String sortOrder = "popularity.desc", moreParams = "";
public static boolean setting_cached = false;
public int gridPos = -1;
public Fragament_main() {
// Required empty public constructor
instance = this;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mainFragmentView = inflater.inflate(R.layout.fragment_main, container, false);
mRequestQueue = Volley.newRequestQueue(getContext());
// setup adapters
imageAdapter = new ImageAdapter(getContext());
gridview = (GridView) mainFragmentView.findViewById(R.id.gridView);
gridview.setAdapter(imageAdapter);
//updateUI(setting_cached);
//gridview.setOnItemClickListener(new GridClickListener());
// manage grid col count wrt Orientation
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
setGridColCount(3);
else
setGridColCount(2);
return mainFragmentView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("GRIDVIEW_POSITION", gridview.getFirstVisiblePosition());
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
gridPos = savedInstanceState.getInt("GRIDVIEW_POSITION");
}
#Override
public void onDestroyView() {
super.onDestroyView();
mRequestQueue.cancelAll(new RequestQueue.RequestFilter() {
#Override
public boolean apply(Request<?> request) {
return true;
}
});
}
/*class GridClickListener implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
if (isDualPane){
android.support.v4.app.FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
DetailActivityFragment detailActivityFragment = DetailActivityFragment.newInstance(movies.get(position));
ft.replace(R.id.detailContainer, detailActivityFragment);
ft.commit();
} else {
Intent intent = new Intent(getContext(), DetailActivity.class);
intent.putExtra(Intent.EXTRA_TEXT, (Parcelable) movies.get(position));
startActivity(intent);
}
}
}*/
/* public void updateUI(boolean cached){
movies.clear();
imageAdapter.clearItems();
setting_cached = cached;
if (!cached)
getMovies(sortOrder, moreParams);
else
getFavorites();
}
*/
public void getMovies(String sortOrder, String moreParams){
String url = "http://souq.hardtask.co/app/app.asmx/GetCategories?categoryId=0&countryId=1";
JsonObjectRequest req = new JsonObjectRequest(url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray items = response.getJSONArray("results");
JSONObject movieObj;
for (int i=0; i<items.length(); i++){
movieObj = items.getJSONObject(i);
Movie movie = new Movie();
movie.id = movieObj.getInt("id");
movie.TitleEN = movieObj.getString("original_title");
movie.TitleAR = movieObj.getString("overview");
movie.Photo = "http://souq.hardtask.co/app/app.asmx/GetCategories?categoryId=0&countryId=1" + movieObj.getString("poster_path");
movies.add(movie);
// Add image to adapter
imageAdapter.addItem(movie.Photo);
}
} catch (JSONException e){
e.printStackTrace();
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
gridview.setAdapter(imageAdapter);
if (gridPos > -1)
gridview.setSelection(gridPos);
gridPos = -1;
}
});
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(LOG_TAG, "Error in JSON Parsing");
}
});
mRequestQueue.add(req);
}
/* public void getFavorites(){
movies.addAll((new MoviesDB()).getFavoriteMovies(getContext().getContentResolver()));
for (Movie movie : movies){
imageAdapter.addItem(movie.Photo);
}
gridview.setAdapter(imageAdapter);
if (gridPos > -1)
gridview.setSelection(gridPos);
gridPos = -1;
}*/
public void updateFavoritesGrid(){
if (setting_cached) {
int p = gridview.getLastVisiblePosition();
///updateUI(true);
gridview.smoothScrollToPosition(p);
}
}
public void setGridColCount(int n){
((GridView) mainFragmentView.findViewById(R.id.gridView)).setNumColumns(n);
}
}
I don't know how to add Json data into GridView.
Could you help me?
Go through this example to view images in grid,
Convert your jsonArray into an ArrayList by using,
ArrayList<Cars> carsList = new Gson().fromJson(jsonArrayYouHave.toString(),new TypeToken<List<Cars>>() {
}.getType());
Pass this Array to your Adapter.
Use this POJO,
public class Cars {
private String TitleAR;
private String HaveModel;
private String TitleEN;
private String Id;
private ArrayList<SubCategories> SubCategories;
private String Photo;
private String ProductCount;
//Todo please add getter/setters for class Cars variables here
public class SubCategories {
private String TitleAR;
private String HaveModel;
private String TitleEN;
private String Id;
private ArrayList<String> SubCategories;
private String Photo;
private String ProductCount;
//Todo please add getter/setters for class SubCategories variables here
}
I'll suggest to use Retrofit as it'll provide you parsed arraylist which is converted into Response POJO you have provided. You can find many examples for Retrofit.
Step 1
Add the following dependencies in your app level gradle file.Dependencies are for retrofit, gsonConvertor butterknife and glide.
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
implementation('com.squareup.retrofit2:retrofit:2.1.0') {
// exclude Retrofit’s OkHttp dependency module and define your own module import
exclude module: 'okhttp'
}
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation "com.jakewharton:butterknife:$BUTTER_KNIFE_VERSION"
annotationProcessor "com.jakewharton:butterknife-compiler:$BUTTER_KNIFE_VERSION"
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
Step 2 Create a class by name ApiClient and paste the following code in this class
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getRetrofit() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("http://souq.hardtask.co")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
}
Step 3 Create a new Interface class by name APIInterface and paste the following code in this class
#GET("/app/app.asmx/GetCategories")
Call<List<Product>> getProducts(#QueryMap Map<String, String> params);
Step 4 Create POJO classes according to json response. We have two classes Products and their subcategory.So I am creating first class by name Product
public class Product {
#SerializedName("Id")
#Expose
private Integer id;
#SerializedName("TitleEN")
#Expose
private String titleEN;
#SerializedName("TitleAR")
#Expose
private String titleAR;
#SerializedName("Photo")
#Expose
private String photo;
#SerializedName("ProductCount")
#Expose
private String productCount;
#SerializedName("HaveModel")
#Expose
private String haveModel;
#SerializedName("SubCategories")
#Expose
private List<SubCategory> subCategories = null;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitleEN() {
return titleEN;
}
public void setTitleEN(String titleEN) {
this.titleEN = titleEN;
}
public String getTitleAR() {
return titleAR;
}
public void setTitleAR(String titleAR) {
this.titleAR = titleAR;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getProductCount() {
return productCount;
}
public void setProductCount(String productCount) {
this.productCount = productCount;
}
public String getHaveModel() {
return haveModel;
}
public void setHaveModel(String haveModel) {
this.haveModel = haveModel;
}
public List<SubCategory> getSubCategories() {
return subCategories;
}
public void setSubCategories(List<SubCategory> subCategories) {
this.subCategories = subCategories;
}
}
And SubCategory
public class SubCategory {
#SerializedName("Id")
#Expose
private Integer id;
#SerializedName("TitleEN")
#Expose
private String titleEN;
#SerializedName("TitleAR")
#Expose
private String titleAR;
#SerializedName("Photo")
#Expose
private String photo;
#SerializedName("ProductCount")
#Expose
private String productCount;
#SerializedName("HaveModel")
#Expose
private String haveModel;
#SerializedName("SubCategories")
#Expose
private List<Object> subCategories = null;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitleEN() {
return titleEN;
}
public void setTitleEN(String titleEN) {
this.titleEN = titleEN;
}
public String getTitleAR() {
return titleAR;
}
public void setTitleAR(String titleAR) {
this.titleAR = titleAR;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getProductCount() {
return productCount;
}
public void setProductCount(String productCount) {
this.productCount = productCount;
}
public String getHaveModel() {
return haveModel;
}
public void setHaveModel(String haveModel) {
this.haveModel = haveModel;
}
public List<Object> getSubCategories() {
return subCategories;
}
public void setSubCategories(List<Object> subCategories) {
this.subCategories = subCategories;
}
}
Step 5 now we need a view for recyclerview holder(in your case gridview layout). For that we need to create a new layout file inside layout folder. you can name it li_product_view
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="200dp"
android:layout_height="200dp">
<ImageView
android:id="#+id/ImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#mipmap/ic_launcher" />
<TextView
android:id="#+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/ImageView"
android:layout_alignTop="#id/ImageView"
android:layout_alignRight="#id/ImageView"
android:layout_alignBottom="#id/ImageView"
android:text="#string/app_name"
android:gravity="bottom|right" />
</RelativeLayout>
</RelativeLayout>
Step 6 Now we need itemHolder to hold the view for that purpose we will create a new class by name ProductsItemHolderand will have the following code
public class ProductsItemHolder extends RecyclerView.ViewHolder {
#BindView(R.id.ImageView)
ImageView imageView;
#BindView(R.id.tv_title)
TextView textView;
public ProductsItemHolder(#NonNull View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
}
public void bindData(Product datum, int position, int size) {
Glide.with(itemView)
.asBitmap()
.load(datum.getPhoto())
.into(imageView);
textView.setText(datum.getTitleAR());
}
}
Step 7 Now we need adapter which contains the data to present inside recyclerview. Create a new class by name ProductsAdapter and paste the following code inside this class
public class ProductsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Product> mList;
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.li_product_view, viewGroup, false);
return new ProductsItemHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int position) {
int size= mList.size();
((ProductsItemHolder) viewHolder).bindData(mList.get(position), position,size);
}
#Override
public int getItemCount() {
return mList.size();
}
public void setData(List<Product> userLists) {
this.mList = userLists;
notifyDataSetChanged();
}
}
Step 8 now inside the activity or fragment we need to get response from json and pass this response to recyclerview.
public class MainActivity extends AppCompatActivity {
APIInterface apiInterfacePages;
RecyclerView recyclerView;
List<MultipleResource.Datum> datumList= new ArrayList<>();
ProgressDialog dialog;
ProductsAdapter productsAdapter;
private List<Product> dataArrayList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apiInterfacePages= PageApiClient.getRetrofit().create(APIInterface.class);
recyclerView= findViewById(R.id.recyclerView);
productsAdapter= new ProductsAdapter();
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
getData();
}
private void getData() {
dataArrayList = new ArrayList<>();
Map<String, String> params = new HashMap<String, String>();
params.put("categoryId", "0");
params.put("countryId", "1");
Call<List<Product>> call= apiInterfacePages.getProducts(params);
call.enqueue(new Callback<List<Product>>() {
#Override
public void onResponse(Call<List<Product>> call, Response<List<Product>> response) {
dataArrayList = response.body();
productsAdapter.setData(dataArrayList);
recyclerView.setAdapter(productsAdapter);
}
#Override
public void onFailure(Call<List<Product>> call, Throwable t) {
Log.i("Call response",t.getMessage());
}
});
}
}
Hi Im trying to show a list from retrofit onResponse and I am using recyclerview inside a fragment. The list shoud show chefs but I got an error from RecyclerView
Conexion Class
public class Conexion {
public static String BASE_URL = "http://10.30.0.133:8091/Service1.asmx/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
EndPoint Interface
public interface EndPointsInterface {
#GET("chef/{idUser}")
Call<ChefResponse> GetChefsCercanos(#Path("idUser") Integer id_usuario);
}
Entity Usuario
public class Usuario {
#SerializedName("id_usuario")
private Integer id_usuario;
#SerializedName("NombreUsuario")
private String NombreUsuario;
#SerializedName("ApellidoUsuario")
private String ApellidoUsuario;
#SerializedName("TelefonoUsuario")
private String TelefonoUsuario;
#SerializedName("Email")
private String Email;
#SerializedName("Contraseña")
private String Contraseña;
#SerializedName("pos_x")
private Double pos_x;
#SerializedName("pos_y")
private Double pos_y;
public Usuario(){}
public Usuario(Integer id_usuario,String NombreUsuario,String ApellidoUsuario,String TelefonoUsuario,String Email,String Contraseña,Double pos_x,Double pos_y){
this.id_usuario=id_usuario;
this.NombreUsuario=NombreUsuario;
this.ApellidoUsuario=ApellidoUsuario;
this.TelefonoUsuario=TelefonoUsuario;
this.Contraseña=Contraseña;
this.pos_x=pos_x;
this.pos_y=pos_y;
}
public Integer getId_usuario() {
return id_usuario;
}
public void setId_usuario(Integer id_usuario) {
this.id_usuario = id_usuario;
}
public String getNombreUsuario() {
return NombreUsuario;
}
public void setNombreUsuario(String nombreUsuario) {
NombreUsuario = nombreUsuario;
}
public String getApellidoUsuario() {
return ApellidoUsuario;
}
public void setApellidoUsuario(String apellidoUsuario) {
ApellidoUsuario = apellidoUsuario;
}
public String getTelefonoUsuario() {
return TelefonoUsuario;
}
public void setTelefonoUsuario(String telefonoUsuario) {
TelefonoUsuario = telefonoUsuario;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
public String getContraseña() {
return Contraseña;
}
public void setContraseña(String contraseña) {
Contraseña = contraseña;
}
public Double getPos_x() {
return pos_x;
}
public void setPos_x(Double pos_x) {
this.pos_x = pos_x;
}
public Double getPos_y() {
return pos_y;
}
public void setPos_y(Double pos_y) {
this.pos_y = pos_y;
}
}
Entity Chef
public class Chef extends Usuario{
#SerializedName("id_chef")
private Integer id_chef;
#SerializedName("TipoServicio")
private String TipoServicio;
#SerializedName("Rating")
private Double Rating;
#SerializedName("EstadoChef")
private Boolean EstadoChef;
public Chef(){}
public Chef(Integer id_usuario,String NombreUsuario,String ApellidoUsuario,String TelefonoUsuario,String Email,String Contraseña,Double pos_x,Double pos_y,Integer id_chef,String TipoServicio,Double Rating,Boolean EstadoChef){
super(id_usuario,NombreUsuario,ApellidoUsuario,TelefonoUsuario,Email,Contraseña,pos_x,pos_y);
this.id_chef=id_chef;
this.TipoServicio=TipoServicio;
this.Rating=Rating;
this.EstadoChef=EstadoChef;
}
public Integer getId_chef() {
return id_chef;
}
public void setId_chef(Integer id_chef) {
this.id_chef = id_chef;
}
public String getTipoServicio() {
return TipoServicio;
}
public void setTipoServicio(String tipoServicio) {
TipoServicio = tipoServicio;
}
public Double getRating() {
return Rating;
}
public void setRating(Double rating) {
Rating = rating;
}
public Boolean getEstadoChef() {
return EstadoChef;
}
public void setEstadoChef(Boolean estadoChef) {
EstadoChef = estadoChef;
}
}
Chef Response
public class ChefResponse {
#SerializedName("results")
private Chef[] results;
public Chef[] getresults(){
return results;
}
}
RecyclerView Adapter
public class ListaChefsCercanos extends RecyclerView.Adapter<ListaChefsCercanos.ListaChefsCercanosViewHolder> {
private List<Chef> chefs;
private List<Usuario> usuarios;
private int rowLayout;
private Context context;
#Override
public ListaChefsCercanosViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
return new ListaChefsCercanosViewHolder(view);
}
#Override
public void onBindViewHolder(ListaChefsCercanosViewHolder holder, int position) {
holder.nombreschefscerca.setText(chefs.get(position).getNombreUsuario());
holder.ratingchef.setText(chefs.get(position).getRating().toString());
}
#Override
public int getItemCount() {
return chefs.size();
}
public static class ListaChefsCercanosViewHolder extends RecyclerView.ViewHolder{
LinearLayout chefslayout;
TextView nombreschefscerca;
TextView ratingchef;
public ListaChefsCercanosViewHolder(View v){
super(v);
chefslayout=(LinearLayout) v.findViewById(R.id.cheflayoutcerca);
nombreschefscerca=(TextView) v.findViewById(R.id.tv_NombreChefCercano);
ratingchef=(TextView) v.findViewById(R.id.tv_RatingChefCercano);
}
}
public ListaChefsCercanos(ArrayList <Chef> chefs){
this.chefs=chefs;
//this.rowLayout = rowLayout;
//this.context = context;
}
}
and the fragment
public class RecomendadosFragment extends Fragment {
private RatingBar ratingBar;
//ListAdapter adapter;
ArrayList<Chef> listachef;
ListView lvLista;
String tag_json_array="jarray req";
RecyclerView recyclerviewChefsCarnos;
ListaChefsCercanos mListaChefsCercanos;
private ArrayList<Chef> data;
private ListaChefsCercanos adapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View x = inflater.inflate(R.layout.recomendados,null);
//ratingBar = (RatingBar) x.findViewById(R.id.rb_RatingChefCercano);
recyclerviewChefsCarnos=(RecyclerView) x.findViewById(R.id.rv_chefsCernaos);
recyclerviewChefsCarnos.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
EndPointsInterface apiService = Conexion.getClient().create(EndPointsInterface.class);
Call<ChefResponse> call = apiService.GetChefsCercanos(5);
call.enqueue(new Callback<ChefResponse>() {
#Override
public void onResponse(Call<ChefResponse> call, Response<ChefResponse> response) {
int statusCode = response.code();
if (response.isSuccessful()) {
ChefResponse jsonResponse = response.body();
if(jsonResponse != null) {
data = new ArrayList<>(Arrays.asList(jsonResponse.getresults()));
adapter= new ListaChefsCercanos(data);
recyclerviewChefsCarnos.setAdapter(adapter);
}
} else {
// Do whatever you want if API is unsuccessful.
}
// List<Chef> chefs= response.body().getResults();
// recyclerviewChefsCarnos.setAdapter(new ListaChefsCercanos( chefs,R.layout.itemchefscercanos,getActivity().getApplicationContext()));
}
#Override
public void onFailure(Call<ChefResponse> call, Throwable t) {
Log.d("Error",t.getMessage());
}
});
return x;
}
this is the error I found while Im debuging
E/RecyclerView: No adapter attached; skipping layout
Update: Use a empty adapter for the RecyclerView in the OncreateView()
recyclerView.setAdapter(new YourAdapter(getCurrentActivity()));
i create application call api the moves DB with retrofit library and recyclerViewe
when user choose the movie Show activity for detail movies
Now i implement recyclerView with ritrofit to create fetch the popular movie data,
this MoviesApiService class :
public interface MoviesApiService {
#GET("/movie/popular")
void getPopularMovies(Callback<Movie.MovieResult> cb); }
this model class :
package com.walkatheri.popularmovies;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
*/
public class Movie implements Parcelable{
private String title;
#SerializedName("poster_path")
private String poster;
#SerializedName("overview")
private String description;
#SerializedName("backdrop_path")
private String backdrop;
public Movie() {}
protected Movie(Parcel in) {
title = in.readString();
poster = in.readString();
description = in.readString();
backdrop = in.readString();
}
public static final Creator<Movie> CREATOR = new Creator<Movie>() {
#Override
public Movie createFromParcel(Parcel in) {
return new Movie(in);
}
#Override
public Movie[] newArray(int size) {
return new Movie[size];
}
};
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPoster() {
return "http://image.tmdb.org/t/p/w500" + poster;
}
public void setPoster(String poster) {
this.poster = poster;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getBackdrop() {
return "http://image.tmdb.org/t/p/w500" + backdrop;
}
public void setBackdrop(String backdrop) {
this.backdrop = backdrop;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(title);
parcel.writeString(poster);
parcel.writeString(description);
parcel.writeString(backdrop);
}
public static class MovieResult {
private List<Movie> results;
public List<Movie> getResults() {
return results;
}
}
}
class detail movie :
public class MovieDetailActivity extends AppCompatActivity {
public static final String EXTRA = "movie";
private Movie mMovie;
ImageView backdrop;
ImageView poster;
TextView title;
TextView description;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_detail);
if (getIntent().hasExtra(EXTRA)) {
mMovie = getIntent().getParcelableExtra(EXTRA);
} else {
throw new IllegalArgumentException("Detail activity must receive a movie parcelable");
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
CollapsingToolbarLayout toolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.toolbar_layout);
toolbarLayout.setTitle(mMovie.getTitle());
backdrop = (ImageView) findViewById(R.id.backdrop);
title = (TextView) findViewById(R.id.movie_title);
description = (TextView) findViewById(R.id.movie_description);
poster = (ImageView) findViewById(R.id.movie_poster);
title.setText(mMovie.getTitle());
description.setText(mMovie.getDescription());
Picasso.with(this)
.load(mMovie.getPoster())
.into(poster);
Picasso.with(this)
.load(mMovie.getBackdrop())
.into(backdrop);
}
}
this mainActivity class :
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private MoviesAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
mAdapter = new MoviesAdapter(this);
mRecyclerView.setAdapter(mAdapter);
getPopularMovies();
}
private void getPopularMovies() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://api.themoviedb.org/3")
.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addEncodedQueryParam("api_key", "Key_API");
}
})
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
MoviesApiService service = restAdapter.create(MoviesApiService.class);
service.getPopularMovies(new Callback<Movie.MovieResult>() {
#Override
public void success(Movie.MovieResult movieResult, Response response) {
mAdapter.setMovieList(movieResult.getResults());
}
#Override
public void failure(RetrofitError error) {
error.printStackTrace();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public static class MovieViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public MovieViewHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.imageView);
}
}
public static class MoviesAdapter extends RecyclerView.Adapter<MovieViewHolder> {
private List<Movie> mMovieList;
private LayoutInflater mInflater;
private Context mContext;
public MoviesAdapter(Context context) {
this.mContext = context;
this.mInflater = LayoutInflater.from(context);
}
#Override
public MovieViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
View view = mInflater.inflate(R.layout.row_movie, parent, false);
final MovieViewHolder viewHolder = new MovieViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = viewHolder.getAdapterPosition();
Intent intent = new Intent(mContext, MovieDetailActivity.class);
intent.putExtra(MovieDetailActivity.EXTRA, mMovieList.get(position));
mContext.startActivity(intent);
}
});
return viewHolder;
}
#Override
public void onBindViewHolder(MovieViewHolder holder, int position) {
Movie movie = mMovieList.get(position);
Picasso.with(mContext)
.load(movie.getPoster())
.placeholder(R.color.colorAccent)
.into(holder.imageView);
}
#Override
public int getItemCount() {
return (mMovieList == null) ? 0 : mMovieList.size();
}
public void setMovieList(List<Movie> movieList) {
this.mMovieList = new ArrayList<>();
this.mMovieList.addAll(movieList);
notifyDataSetChanged();
}
}
}
now how can be able to fetch both popular movie data and high-rated movie data from https://developers.themoviedb.org ? can you help me ?
You have a method in your MainActivity called getPopularMovies() where you call service.getPopularMovies(), which uses the MoviesApiService #GET("/movie/popular"). You could create a similar API for high-rated movies, something like:
#GET("/movie/high_rated")
void getHighRatedMovies(Callback<Movie.MovieResult> cb);
Then create a similar getHighRatedMovies() method and depending on what the user selects, make a call to that method. The only difference would be you would call service.getHighRatedMovies instead of service.getPopularMovies().
To simplify the code to just one method, you could make a method called getMovies(), and then at the point when you initialize service.(something), set the correct method call.
New to using okhttp and Gson. I am practicing by creating a List View that will display information from Rotten Tomatoes API
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import com.google.gson.Gson;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
ListView listView;
Response responseObj;
CustomAdapter adapter;
String url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json?apikey=9htuhtcb4ymusd73d4z6jxcj";
Gson gson;
OkHttpClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.myList);
client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(com.squareup.okhttp.Response response) throws IOException {
String responseStr = response.body().string();
gson = new Gson();
**responseObj = gson.fromJson(responseStr,Response.class);**
adapter = new CustomAdapter(MainActivity.this, responseObj.getMovies());
listView.setAdapter(adapter);
}
});
}
}
This is the Error I get for line 44
FATAL EXCEPTION: OkHttp Dispatcher
com.google.gson.JsonSyntaxException: java.lang.NumberFormatException:
Invalid double: ""
public class Response {
private String link_template;
/**
* id : 771312089
* title : The Hunger Games: Mockingjay - Part 2
* year : 2015
* mpaa_rating : PG-13
* runtime : 136
* critics_consensus :
* release_dates : {"theater":"2015-11-20"}
* ratings : {"critics_rating":"Fresh","critics_score":70,"audience_rating":"Upright","audience_score":71}
* synopsis : The second half of Suzanne Collins' final Hunger Games book is adapted in this Lionsgate production. ~ Jeremy Wheeler, Rovi
* posters : {"thumbnail":"http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg","profile":"http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg","detailed":"http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg","original":"http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg"}
* abridged_cast : [{"name":"Jennifer Lawrence","id":"770800260","characters":["Katniss Everdeen"]},{"name":"Julianne Moore","id":"162654248","characters":["President Alma Coin"]},{"name":"Gwendoline Christie","id":"771060732","characters":["Commander Lyme"]},{"name":"Josh Hutcherson","id":"162654356","characters":["Peeta Mellark"]},{"name":"Robert Knepper","id":"162707688","characters":["Antonius"]}]
* links : {"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/771312089.json","alternate":"http://www.rottentomatoes.com/m/the_hunger_games_mockingjay_part_2/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/771312089/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/771312089/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/771312089/similar.json"}
*/
private List<MoviesEntity> movies;
public void setLinks(LinksEntity links) {
this.links = links;
}
public void setLink_template(String link_template) {
this.link_template = link_template;
}
public void setMovies(List<MoviesEntity> movies) {
this.movies = movies;
}
public LinksEntity getLinks() {
return links;
}
public String getLink_template() {
return link_template;
}
public List<MoviesEntity> getMovies() {
return movies;
}
public static class LinksEntity {
private String self;
private String alternate;
public void setSelf(String self) {
this.self = self;
}
public void setAlternate(String alternate) {
this.alternate = alternate;
}
public String getSelf() {
return self;
}
public String getAlternate() {
return alternate;
}
}
public static class MoviesEntity {
private String id;
private String title;
private int year;
private String mpaa_rating;
private int runtime;
private String critics_consensus;
/**
* theater : 2015-11-20
*/
private ReleaseDatesEntity release_dates;
/**
* critics_rating : Fresh
* critics_score : 70
* audience_rating : Upright
* audience_score : 71
*/
private RatingsEntity ratings;
private String synopsis;
/**
* thumbnail : http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg
* profile : http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg
* detailed : http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg
* original : http://resizing.flixster.com/nim-D7-9jGbUZS5wczNes_PmWyI=/53x81/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/29/11202951_ori.jpg
*/
private PostersEntity posters;
/**
* self : http://api.rottentomatoes.com/api/public/v1.0/movies/771312089.json
* alternate : http://www.rottentomatoes.com/m/the_hunger_games_mockingjay_part_2/
* cast : http://api.rottentomatoes.com/api/public/v1.0/movies/771312089/cast.json
* reviews : http://api.rottentomatoes.com/api/public/v1.0/movies/771312089/reviews.json
* similar : http://api.rottentomatoes.com/api/public/v1.0/movies/771312089/similar.json
*/
private LinksEntity links;
/**
* name : Jennifer Lawrence
* id : 770800260
* characters : ["Katniss Everdeen"]
*/
private List<AbridgedCastEntity> abridged_cast;
public void setId(String id) {
this.id = id;
}
public void setTitle(String title) {
this.title = title;
}
public void setYear(int year) {
this.year = year;
}
public void setMpaa_rating(String mpaa_rating) {
this.mpaa_rating = mpaa_rating;
}
public void setRuntime(int runtime) {
this.runtime = runtime;
}
public void setCritics_consensus(String critics_consensus) {
this.critics_consensus = critics_consensus;
}
public void setRelease_dates(ReleaseDatesEntity release_dates) {
this.release_dates = release_dates;
}
public void setRatings(RatingsEntity ratings) {
this.ratings = ratings;
}
public void setSynopsis(String synopsis) {
this.synopsis = synopsis;
}
public void setPosters(PostersEntity posters) {
this.posters = posters;
}
public void setLinks(LinksEntity links) {
this.links = links;
}
public void setAbridged_cast(List<AbridgedCastEntity> abridged_cast) {
this.abridged_cast = abridged_cast;
}
public String getId() {
return id;
}
public String getTitle() {
return title;
}
public int getYear() {
return year;
}
public String getMpaa_rating() {
return mpaa_rating;
}
public int getRuntime() {
return runtime;
}
public String getCritics_consensus() {
return critics_consensus;
}
public ReleaseDatesEntity getRelease_dates() {
return release_dates;
}
public RatingsEntity getRatings() {
return ratings;
}
public String getSynopsis() {
return synopsis;
}
public PostersEntity getPosters() {
return posters;
}
public LinksEntity getLinks() {
return links;
}
public List<AbridgedCastEntity> getAbridged_cast() {
return abridged_cast;
}
public static class ReleaseDatesEntity {
private String theater;
public void setTheater(String theater) {
this.theater = theater;
}
public String getTheater() {
return theater;
}
}
public static class RatingsEntity {
private String critics_rating;
private int critics_score;
private String audience_rating;
private int audience_score;
public void setCritics_rating(String critics_rating) {
this.critics_rating = critics_rating;
}
public void setCritics_score(int critics_score) {
this.critics_score = critics_score;
}
public void setAudience_rating(String audience_rating) {
this.audience_rating = audience_rating;
}
public void setAudience_score(int audience_score) {
this.audience_score = audience_score;
}
public String getCritics_rating() {
return critics_rating;
}
public int getCritics_score() {
return critics_score;
}
public String getAudience_rating() {
return audience_rating;
}
public int getAudience_score() {
return audience_score;
}
}
public static class PostersEntity {
private String thumbnail;
private String profile;
private String detailed;
private String original;
public void setThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}
public void setProfile(String profile) {
this.profile = profile;
}
public void setDetailed(String detailed) {
this.detailed = detailed;
}
public void setOriginal(String original) {
this.original = original;
}
public String getThumbnail() {
return thumbnail;
}
public String getProfile() {
return profile;
}
public String getDetailed() {
return detailed;
}
public String getOriginal() {
return original;
}
}
public static class LinksEntity {
private String self;
private String alternate;
private String cast;
private String reviews;
private String similar;
public void setSelf(String self) {
this.self = self;
}
public void setAlternate(String alternate) {
this.alternate = alternate;
}
public void setCast(String cast) {
this.cast = cast;
}
public void setReviews(String reviews) {
this.reviews = reviews;
}
public void setSimilar(String similar) {
this.similar = similar;
}
public String getSelf() {
return self;
}
public String getAlternate() {
return alternate;
}
public String getCast() {
return cast;
}
public String getReviews() {
return reviews;
}
public String getSimilar() {
return similar;
}
}
public static class AbridgedCastEntity {
private String name;
private String id;
private List<String> characters;
public void setName(String name) {
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public void setCharacters(List<String> characters) {
this.characters = characters;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
public List<String> getCharacters() {
return characters;
}
}
}
}
package com.example.nano1.gsonexample;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.List;
public class CustomAdapter extends BaseAdapter {
private List<Response.MoviesEntity> mMovieItem;
private Context context;
private LayoutInflater inflater;
public CustomAdapter(Context context, List<Response.MoviesEntity> mMovieItem) {
this.context = context;
this.mMovieItem = mMovieItem;
}
#Override
public int getCount() {
return mMovieItem.size();
}
#Override
public Object getItem(int position) {
return mMovieItem.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.each_list_item, parent, false);
Response.MoviesEntity item = (Response.MoviesEntity) getItem(position);
ImageView thumbnail = (ImageView) rowView.findViewById(R.id.thumnnail);
TextView title = (TextView) rowView.findViewById(R.id.title);
TextView rating = (TextView) rowView.findViewById(R.id.rating);
String imageURL = item.getPosters().getOriginal();
Picasso.with(context).load(imageURL).into(thumbnail);
title.setText(item.getTitle());
rating.setText(item.getRatings().getAudience_rating());
return rowView;
}
}
in the declared classes above you have members of type int now in the response you are getting values for these members as empty string "" which is not allowed, it should be an integer. that makes the exception, you either:
1- change member type to String, and handle empty string as 0 in the setters/getters
or
2- ask the back-end team to send correct data
or
3- use a custom TypedAdapter in the Gson converter to handle integers when they have empty string
P.S: i am aware the sample json does not contain empty strings but on the real call on the service, you might have an empty strings for integer members