我想构建一个使用改造消耗REST api的电影应用程序,并使用Picasso显示图像并引入Retrofit并显示真实的电影海报以及每部电影的详细信息。
我正在使用The Movie Database Api将一些真实数据输入我们的应用程序。查看他们的文档并熟悉他们的API,特别是电影/热门端点
但是当运行应用程序白屏时,显示图片并不显示电影,我不知道问题出在哪里
此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
上课:
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
上课:
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);
}
答案 0 :(得分:2)
很难指出错误,没有像stacktraces那样的暗示。
一些指针
使用改造异步调用。
您需要.addConverterFactory(GsonConverterFactory.create())将json转换为pojos。
只有当您使用网址http://image.tmdb.org/t/p/w185“+”yourposterpath“时才会加载图片。请检查moviedb链接
更新您的图书馆并相应更改您的api(推荐)
最后一个干净的架构将帮助您正确编写测试。您的代码是非结构化的,您需要正确分离组件。建议您阅读有关MVP或MVVM模式的内容。匕首也可以提供帮助。
关于改造https://inthecheesefactory.com/blog/retrofit-2.0/en
的好读物所以改变
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";
}
}
}
然后
public interface MoviesApiService {
@GET("movie/popular")
Call<MoviesList> getPopularMovies();
}
我的模型类
使用http://www.jsonschema2pojo.org/将json转换为pojo
我在github上复制了下面的一个存储库。
github上有很多类似的存储库。 https://github.com/ewintory/udacity-popular-movies等等...... 公共类电影实现了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;
}
}
最后更新的库
// 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'
您可以查看日志
答案 1 :(得分:0)
根据你的模糊输入几乎不可能确切地知道发生了什么,但我的赌注是你没有在应用程序的清单中指定互联网许可:
<uses-permission android:name="android.permission.INTERNET"/>
(在src / main / AndroidManifest.xml中,在manifest标签下)