当使用回收者视图和视图模型获取数据时,映射器函数返回空值

时间:2019-08-27 03:38:39

标签: java android api retrofit viewmodel

我想使用带有改型和视图模型的API。

数据未显示在屏幕中,错误是“映射器函数返回了空值”。

这是我的片段,我在这里连接适配器:

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_movies, container, false);
        rv_grid_movies = rootView.findViewById(R.id.rv_grid_movies);
        RecyclerView.LayoutManager manager = new GridLayoutManager(getActivity(), 2);
        rv_grid_movies.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(3), true));
        rv_grid_movies.setItemAnimator(new DefaultItemAnimator());
        rv_grid_movies.setLayoutManager(manager);
        rv_grid_movies.setHasFixedSize(true);

        Model moviesModel = ViewModelProviders.of(this).get(Model.class);

        moviesModel.getMovies().observe(this, new Observer<List<MoviesItems>>() {
            @Override
            public void onChanged(@Nullable List<MoviesItems> moviesItems) {
                moviesAdapter = new MoviesAdapter(getActivity(), moviesItems);
                rv_grid_movies.setAdapter(moviesAdapter);
            }
        });

        return rootView;
    }

这是我的适配器和我的回收站视图适配器:

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

    @NonNull
    @Override
    public MoviesViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(context).inflate(R.layout.grid_movies, viewGroup, false);
        return new MoviesViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MoviesViewHolder moviesViewHolder, int i) {
        MoviesItems items = moviesList.get(i);
        String url = "https://image.tmdb.org/t/p/original";
        moviesViewHolder.txt_title_movies.setText(items.getTitle());
        moviesViewHolder.txt_date_movies.setText(items.getRelease_date());
        moviesViewHolder.txt_description_movies.setText(items.getOverview());
        Glide.with(context)
                .load(url + items.getPoster_path())
                .into(moviesViewHolder.img_movies);
    }

    @Override
    public int getItemCount() {
        return (moviesList != null) ? moviesList.size() : 0;
    }

    public class MoviesViewHolder extends RecyclerView.ViewHolder {

        TextView txt_title_movies, txt_date_movies, txt_description_movies;
        ImageView img_movies;


        public MoviesViewHolder(@NonNull View itemView) {
            super(itemView);
            txt_title_movies = itemView.findViewById(R.id.txt_titlemovie);
            txt_date_movies = itemView.findViewById(R.id.txt_datemovie);
            txt_description_movies = itemView.findViewById(R.id.txt_descriptionmovie);
            img_movies = itemView.findViewById(R.id.img_movie);
        }
    }
}

这是接口API,我使用Retrofit:

public interface Api {
    String BASE_URL = "https://api.themoviedb.org/3/discover/";
    String API_KEY = "myapikey";
    String LANGUAGE = "&language=en-US";

    @GET("movie?api_key="+API_KEY+LANGUAGE)
    Call<List<MoviesItems>> getMovies();
}

这是我的视图模型:

private MutableLiveData<List<MoviesItems>> moviesList;

   public LiveData<List<MoviesItems>> getMovies() {
       if (moviesList == null){
           moviesList = new MutableLiveData<List<MoviesItems>>();

           loadMovies();
       }

       return moviesList;
   }

    private void loadMovies() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Api.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        Api api = retrofit.create(Api.class);
        Call<List<MoviesItems>> call = api.getMovies();

        call.enqueue(new Callback<List<MoviesItems>>() {
            @Override
            public void onResponse(Call<List<MoviesItems>> call, Response<List<MoviesItems>> response) {
                moviesList.setValue(response.body());
            }

            @Override
            public void onFailure(Call<List<MoviesItems>> call, Throwable t) {

            }
        });
    }

这是logcat中的错误消息:

java.lang.NullPointerException: The mapper function returned a null value.
        at io.reactivex.d.b.b.a(ObjectHelper.java:39)
        at io.reactivex.d.e.b.g$a.onNext(ObservableMap.java:59)
        at io.reactivex.d.e.b.i$a.run(ObservableScalarXMap.java:248)
        at io.reactivex.d.e.b.f.b(ObservableJust.java:35)
        at io.reactivex.h.a(Observable.java:11442)
        at io.reactivex.d.e.b.g.b(ObservableMap.java:33)
        at io.reactivex.h.a(Observable.java:11442)
        at io.reactivex.d.e.b.l$b.run(ObservableSubscribeOn.java:96)
        at io.reactivex.a.b.b$b.run(HandlerScheduler.java:109)
        at android.os.Handler.handleCallback(Handler.java:754)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:165)
        at android.app.ActivityThread.main(ActivityThread.java:6375)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)

1 个答案:

答案 0 :(得分:0)

mapper函数返回一个空值,因此请像这样修改您的代码,下面是完整的示例代码:


完整示例代码:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fragment"/>

</RelativeLayout>

MainActivity.java:

public class MainActivity extends AppCompatActivity {
    FrameLayout frameLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        frameLayout=findViewById(R.id.fragment);
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new MyFragment(),"").commit();

    }
}

fragment_movies.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_grid_movies"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>

MyFragment.java:

 import android.support.v4.app.Fragment;
public class MyFragment extends Fragment {
    RecyclerView rv_grid_movies;
    MoviesAdapter moviesAdapter;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_movies, container, false);
        rv_grid_movies = rootView.findViewById(R.id.rv_grid_movies);
        RecyclerView.LayoutManager manager = new GridLayoutManager(getActivity(), 2);
       // rv_grid_movies.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(3), true));
        rv_grid_movies.setItemAnimator(new DefaultItemAnimator());
        rv_grid_movies.setLayoutManager(manager);
        rv_grid_movies.setHasFixedSize(true);

        Model model = ViewModelProviders.of(this).get(Model.class);


        model.getMovies().observe(this, new Observer<List<MovieList>>() {
            @Override
            public void onChanged(@Nullable List<MovieList> movieLists) {
                moviesAdapter=new MoviesAdapter(getActivity(),movieLists);
                rv_grid_movies.setAdapter(moviesAdapter);
            }
        });
        return rootView;
    }
}

MovieItems.java(Model):

  public class MovieItems {

        @SerializedName("page")
        @Expose
        private Integer page;
        @SerializedName("total_results")
        @Expose
        private Integer totalResults;
        @SerializedName("total_pages")
        @Expose
        private Integer totalPages;
        @SerializedName("results")
        @Expose
        private List<MovieList> movieLists = null;

        public Integer getPage() {
            return page;
        }

        public void setPage(Integer page) {
            this.page = page;
        }

        public Integer getTotalResults() {
            return totalResults;
        }

        public void setTotalResults(Integer totalResults) {
            this.totalResults = totalResults;
        }

        public Integer getTotalPages() {
            return totalPages;
        }

        public void setTotalPages(Integer totalPages) {
            this.totalPages = totalPages;
        }

        public List<MovieList> getMovieLists() {
            return movieLists;
        }

        public void setMovieLists(List<MovieList> movieLists) {
            this.movieLists = movieLists;
        }

    }

MovieList.java(模型):

public class MovieList {

    @SerializedName("popularity")
    @Expose
    private Double popularity;
    @SerializedName("vote_count")
    @Expose
    private Integer voteCount;
    @SerializedName("video")
    @Expose
    private Boolean video;
    @SerializedName("poster_path")
    @Expose
    private String posterPath;
    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("adult")
    @Expose
    private Boolean adult;
    @SerializedName("backdrop_path")
    @Expose
    private String backdropPath;
    @SerializedName("original_language")
    @Expose
    private String originalLanguage;
    @SerializedName("original_title")
    @Expose
    private String originalTitle;
    @SerializedName("genre_ids")
    @Expose
    private List<Integer> genreIds = null;
    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("vote_average")
    @Expose
    private Double voteAverage;
    @SerializedName("overview")
    @Expose
    private String overview;
    @SerializedName("release_date")
    @Expose
    private String releaseDate;

    public Double getPopularity() {
        return popularity;
    }

    public void setPopularity(Double popularity) {
        this.popularity = popularity;
    }

    public Integer getVoteCount() {
        return voteCount;
    }

    public void setVoteCount(Integer voteCount) {
        this.voteCount = voteCount;
    }

    public Boolean getVideo() {
        return video;
    }

    public void setVideo(Boolean video) {
        this.video = video;
    }

    public String getPosterPath() {
        return posterPath;
    }

    public void setPosterPath(String posterPath) {
        this.posterPath = posterPath;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Boolean getAdult() {
        return adult;
    }

    public void setAdult(Boolean adult) {
        this.adult = adult;
    }

    public String getBackdropPath() {
        return backdropPath;
    }

    public void setBackdropPath(String backdropPath) {
        this.backdropPath = backdropPath;
    }

    public String getOriginalLanguage() {
        return originalLanguage;
    }

    public void setOriginalLanguage(String originalLanguage) {
        this.originalLanguage = originalLanguage;
    }

    public String getOriginalTitle() {
        return originalTitle;
    }

    public void setOriginalTitle(String originalTitle) {
        this.originalTitle = originalTitle;
    }

    public List<Integer> getGenreIds() {
        return genreIds;
    }

    public void setGenreIds(List<Integer> genreIds) {
        this.genreIds = genreIds;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Double getVoteAverage() {
        return voteAverage;
    }

    public void setVoteAverage(Double voteAverage) {
        this.voteAverage = voteAverage;
    }

    public String getOverview() {
        return overview;
    }

    public void setOverview(String overview) {
        this.overview = overview;
    }

    public String getReleaseDate() {
        return releaseDate;
    }

    public void setReleaseDate(String releaseDate) {
        this.releaseDate = releaseDate;
    }

}

MoviesAdapter.java:

public class MoviesAdapter extends 
RecyclerView.Adapter<MoviesAdapter.MoviesViewHolder>{
    List<MovieList> moviesList;
    Context context;
    public MoviesAdapter(Context context, List<MovieList> moviesList){
        this.context = context;
        this.moviesList = moviesList;
    }

    @NonNull
    @Override
    public MoviesViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(context).inflate(R.layout.grid_movies, viewGroup, false);
        return new MoviesViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MoviesViewHolder moviesViewHolder, int i) {
        MovieList items = moviesList.get(i);
        String url = "https://image.tmdb.org/t/p/original";
        moviesViewHolder.txt_title_movies.setText(items.getTitle());
        moviesViewHolder.txt_date_movies.setText(items.getReleaseDate());
        moviesViewHolder.txt_description_movies.setText(items.getOverview());
        Glide.with(context)
                .load(url + items.getPosterPath())
                .into(moviesViewHolder.img_movies);
    }

    @Override
    public int getItemCount() {
        return (moviesList != null) ? moviesList.size() : 0;
    }

    public class MoviesViewHolder extends RecyclerView.ViewHolder {
        TextView txt_title_movies, txt_date_movies, txt_description_movies;
        ImageView img_movies;

        public MoviesViewHolder(@NonNull View itemView) {
            super(itemView);
            txt_title_movies = itemView.findViewById(R.id.txt_titlemovie);
            txt_date_movies = itemView.findViewById(R.id.txt_datemovie);
            txt_description_movies = itemView.findViewById(R.id.txt_descriptionmovie);
            img_movies = itemView.findViewById(R.id.img_movie);
        }
    }
}

Api(interface):

public interface Api {

    String BASE_URL = "https://api.themoviedb.org/3/discover/";

    @GET("movie")
    Call<MovieItems> getMovies(@Query("api_key") String apiKey, @Query("language")String language);

}

Model.java:

public class Model extends ViewModel {


    private MutableLiveData<List<MovieList>> moviesList;

    public LiveData<List<MovieList>> getMovies() {
        if (moviesList == null){
            moviesList = new MutableLiveData<List<MovieList>>();

            loadMovies();
        }

        return moviesList;
    }

    private void loadMovies() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Api.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        Api api = retrofit.create(Api.class);
     /*Add your api key*/   Call<MovieItems> call = api.getMovies("Your api key","en-US");

        call.enqueue(new Callback<MovieItems>() {
            @Override
            public void onResponse(Call<MovieItems> call, Response<MovieItems> response) {
                moviesList.setValue(response.body().getMovieLists());
            }

            @Override
            public void onFailure(Call<MovieItems> call, Throwable t) {

            }
        });
    }

}

grid_movies.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/txt_titlemovie"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txt_datemovie"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txt_descriptionmovie"/>
   <ImageView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@+id/img_movie"/>
</LinearLayout>