我正在研究udacity热门电影第一阶段项目,这将允许我从itoviedb数据库中发现电影。
我已创建Movie
,MovieAdapter
和MainActivity
(FetchMovieAsyncTask
作为内部类)类。但我一直低于错误
java.lang.NullPointerException:尝试调用接口方法 ' int java.util.List.size()'在空对象引用上
这些是我的代码
电影课:
public class Movie{
private String mMovieTitle;
private String mPosterPath;
private String mOverview;
private String mReleaseDate;
private double mRating;
public Movie(){
mMovieTitle = null;
mPosterPath = null;
mOverview = null;
mReleaseDate = null;
mRating = -1.0;
}
public Movie(String title){
mMovieTitle = title;
}
public Movie(String title, String posterPath, String overview, String releaseDate, double rating){
mMovieTitle = title;
mPosterPath = posterPath;
mOverview = overview;
mReleaseDate = releaseDate;
mRating = rating;
}
public String getMovieTitle(){
return mMovieTitle;
}
public String getPosterPath(){
return mPosterPath;
}
public String getOverview(){
return mOverview;
}
public String getReleaseData(){
return mReleaseDate;
}
public double getRating(){
return mRating;
}
}
MovieAdapter类:
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
/**
* Created by ibayp on 04/08/2017.
*/
public class MovieAdapter extends ArrayAdapter<Movie> {
Context context;
ArrayList<Movie> movies;
public MovieAdapter(Context context, ArrayList<Movie> movies){
super(context, 0, movies);
this.context = context;
this.movies = movies;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View view = convertView;
if(view == null){
view = LayoutInflater.from(getContext()).inflate(R.layout.poster_list, parent, false);
}
ImageView imageView = (ImageView)view.findViewById(R.id.movie_poster);
Picasso.with(getContext())
.load("https://image.tmdb.org/t/p/w500/kqjL17yufvn9OVLyXYpvtyrFfak.jpg")
.into(imageView);
return view;
}
}
和MainActivity类:
package com.android.ibayp.popularmovies;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
GridView gridView;
ArrayList<Movie> movies;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new FetchMovieAsyncTask().execute("popularity.desc");
MovieAdapter adapter = new MovieAdapter(this, movies);
gridView = (GridView)findViewById(R.id.grid_view);
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
Movie movie = (Movie)parent.getItemAtPosition(position);
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra("title", movie.getMovieTitle());
startActivity(intent);
}
});
}
private class FetchMovieAsyncTask extends AsyncTask<String, Void, ArrayList<Movie>> {
private final String TAG = com.android.ibayp.popularmovies.FetchMovieAsyncTask.class.getSimpleName();
private static final String API_KEY = "api key";
private static final String BASE_URL = "https://api.themoviedb.org/3/discover/movie?";
private String API_PARAM = "api_key";
private String SORT_BY = "sort_by";
public URL buildURL(String[] sortMethod){
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(API_PARAM, API_KEY)
.appendQueryParameter(SORT_BY, sortMethod[0])
.build();
URL url = null;
try{
url = new URL(builtUri.toString());
}catch (MalformedURLException e){
e.printStackTrace();
}
Log.v(TAG, "BUILT URI: " +url);
return url;
}
private String makeHttpRequst(URL url)throws IOException {
String jsonResponse = "";
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try{
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
inputStream = urlConnection.getInputStream();
jsonResponse = readStream(inputStream);
}catch (IOException e){
e.printStackTrace();
}finally {
if(urlConnection!=null){
urlConnection.disconnect();
}
if (inputStream!=null){
inputStream.close();
}
}
return jsonResponse;
}
private String readStream(InputStream inputStream) throws IOException{
StringBuilder results = new StringBuilder();
if(inputStream!=null){
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line!=null){
results.append(line);
line = reader.readLine();
}
}
return results.toString();
}
private ArrayList<Movie> getMovieFromJson(String movieJson){
movies = new ArrayList<Movie>();
try{
JSONObject baseResponse = new JSONObject(movieJson);
JSONArray resultsArray = baseResponse.getJSONArray("results");
Log.v(TAG, "Array Results: "+resultsArray.length());
if (resultsArray.length() > 0){
for (int i = 0; i<resultsArray.length(); i++ ){
JSONObject movieInformation = resultsArray.getJSONObject(i);
movies.add(new Movie(movieInformation.getString("title"),
movieInformation.getString("poster_path"),
movieInformation.getString("overview"),
movieInformation.getString("release_date"),
movieInformation.getDouble("vote_average")));
}
}
}catch (JSONException e){
Log.v(TAG, "Problem parsing Json" + e);
}
return movies;
}
@Override
protected ArrayList<Movie> doInBackground(String... strings) {
URL url = buildURL(strings);
String jsonResponse = "";
try{
jsonResponse = makeHttpRequst(url);
}catch (IOException e){
Log.v(TAG, "IO Exception error "+e);
}
movies = getMovieFromJson(jsonResponse);
return movies;
}
@Override
protected void onPostExecute(ArrayList<Movie> movies) {
if (movies==null){
return;
}
super.onPostExecute(movies);
}
}
}
我使用了日志并设法获得了正确的json结果,但是我无法在ui线程上显示它。
我该如何解决这个问题?感谢
*请注意我使用虚拟图像作为海报
答案 0 :(得分:1)
实例化适配器时,电影为空。因为 asynctask 在并行线程中运行。使用 asynctask 的onPostExecute
方法实例化您的适配器。这样您就可以确定 asynctask 已完成。
@Override
protected void onPostExecute(ArrayList<Movie> movies) {
if (movies==null){
return;
}
super.onPostExecute(movies);
MovieAdapter adapter = new MovieAdapter(MainActivity.this, movies);
gridView.setAdapter(adapter);
}
答案 1 :(得分:0)
在movies.add(...)
之后或onPostExecute
adapter.notifyDataSetChanged()
答案 2 :(得分:0)
我在一段时间后完成了Android Nanodegree并记住了这个项目的工作。实例化适配器时,它将调用getSize()
方法来确定为视图创建的行数,然后在每个上调用getView()
来绑定视图。
由于您的异步任务可能尚未完成下载电影,因此您将空列表传递给适配器,从而获得NullPointerException
。
在AsyncTask的onPostExecute()
方法中实例化适配器总是一种很好的方法。在后台线程完成执行后,在UI线程上调用此方法。
所以将这两行代码放在onPostExecute()
中,它应该可以正常工作
MovieAdapter adapter = new MovieAdapter(MainActivity.this, movies);
gridView.setAdapter(adapter);