在 Android 9 (Pie) 上使用 Retrofit 服务时引用空对象?

Null object reference while using a Retrofit service on Android 9 (Pie)?

我正在使用改装从 "https://api.themoviedb.org/" 获取电影详细信息。该应用程序在 android 5 (Lolipop) 上运行良好,但在 Android 9 上崩溃。经过我的研究,我了解到 Android pie 默认仅使用 HTTPS。你可以清楚地看到上面的 URL 是加密的,所以,这应该不是问题。尽管如此,我还是创建了一个 网络安全配置 文件并将其包含在我的 AndroidManifest.xml

它仍然无法正常工作!!

我正在分享下面的代码 ->

MovieClient.java

public class MovieClient {
    private static final String BASE_URL = "https://api.themoviedb.org/";

    private Retrofit trendingMovieClient;

    //Function for creating a client to receive movie data
    public Retrofit getTrendingMovieClient(){
        if(trendingMovieClient == null) {
            trendingMovieClient = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return trendingMovieClient;
    }
}

MovieService.java

    public interface MovieService {

    @GET("3/trending/all/day")
    Call<MovieJsonData> getTrendingMovies(@Query("api_key") String apiKey);

    @GET("3/discover/movie")
    Call<MovieJsonData> getMostPopularMovies(@Query("api_key") String apiKey,
                                             @Query("language") String language,
                                             @Query("sort_by") String sortBy,
                                             @Query("page") String page);

    @GET("3/discover/movie")
    Call<MovieJsonData> getTopRatedMovies(@Query("api_key") String apiKey,
                                          @Query("language") String language,
                                          @Query("sort_by") String sortBy,
                                          @Query("page") String page,
                                          @Query("vote_count.gte") String voteCountGte,
                                          @Query("vote_count.lte") String voteCountLte,
                                          @Query("vote_average.gte") String voteAverageGte);

    @GET("3/movie/{movie_id}")
    Call<MovieDetailsJson> getMovieDetails(@Path("movie_id") String movieId,
                                           @Query("api_key") String apiKey,
                                           @Query("language") String language);
}

MoviePresenter.java

    public class MoviePresenter implements TrendingModule.Presenter{
    private TrendingModule.View moduleView;
    private MovieAdapter.ClickListener listener;
    private MovieAdapter adapter;

    private static final String API_KEY = "";
    private String sort_key;

    private static final String trending = "trending";
    private static final String most_popular = "most_popular";
    private static final String top_rated = "top_rated";

    //POPULAR MOVIES
    private static final String LANGUAGE_MOST_POPULAR = "en-US";
    private static final String SORT_MOST_POPULAR = "popularity.desc";
    private static final String PAGE_MOST_POPULAR = "1";

    //TOP RATED MOVIES
    private static final String LANGUAGE_TOP_RATED = "en-US";
    private static final String SORT_TOP_RATED = "popularity.desc";
    private static final String PAGE_TOP_RATED = "1";
    private static final String VOTE_COUNT_GTE = "100";
    private static final String VOTE_COUNT_LTE = "1500";
    private static final String VOTE_AVERAGE_GTE = "8";

    public MoviePresenter(TrendingModule.View view, MovieAdapter.ClickListener listener, String key){
        this.moduleView = view;
        this.listener = listener;
        this.sort_key = key;
        moduleView.initView();
        initPresenter();
    }

    @Override
    public void initPresenter() {
        fetchData();
    }

    @Override
    public void fetchData() {
        moduleView.progressBarVisible();

        MovieClient movieClient = new MovieClient();
        Retrofit networkClient = movieClient.getTrendingMovieClient();

        //Starting a service to fetch JSON data
        MovieService trendingService = networkClient.create(MovieService.class);

        Call<MovieJsonData> movieData = null;

        //Fetching results through the service
        if(sort_key == null || sort_key.equals(trending)) {
            movieData = trendingService.getTrendingMovies(API_KEY);
        }
        else{
            if(sort_key.equals(most_popular)){
                movieData = trendingService.
                        getMostPopularMovies(
                                API_KEY,
                                LANGUAGE_MOST_POPULAR,
                                SORT_MOST_POPULAR,
                                PAGE_MOST_POPULAR);
            }
            else if(sort_key.equals(top_rated)){
                movieData = trendingService.
                        getTopRatedMovies(
                                API_KEY,
                                LANGUAGE_TOP_RATED,
                                SORT_TOP_RATED,
                                PAGE_TOP_RATED,
                                VOTE_COUNT_GTE,
                                VOTE_COUNT_LTE,
                                VOTE_AVERAGE_GTE);
            }
            else{
                moduleView.noResponse();
            }
        }
            movieData.enqueue(new Callback<MovieJsonData>() {
            @Override @EverythingIsNonNull
            public void onResponse(Call<MovieJsonData> call, Response<MovieJsonData> response) {
                moduleView.recyclerViewVisible();
                MovieJsonData movieJsonData = response.body();
                adapter = new MovieAdapter(movieJsonData, listener);

                moduleView.displayMovieData(adapter);
            }

            @Override @EverythingIsNonNull
            public void onFailure(Call<MovieJsonData> call, Throwable t) {
                moduleView.noResponse();
            }
        });
    }

}

network_security_config.xml

 <?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:android="http://schemas.android.com/apk/res/android">
    <domain-config
        cleartextTrafficPermitted = "true">
        <domain includeSubdomains = "true">themoviedb.org</domain>
    </domain-config>

</network-security-config>

AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.moviesapp">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:networkSecurityConfig="@xml/network_security_config">
        <activity
            android:name=".view.Settings"
            android:parentActivityName=".view.TrendingMovies" />
        <activity android:name=".view.MovieDetail"
            android:parentActivityName=".view.TrendingMovies"/>
        <activity android:name=".view.TrendingMovies"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

错误 ->

Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void retrofit2.Call.enqueue(retrofit2.Callback)' on a null object reference
        at com.example.moviesapp.presenter.MoviePresenter.fetchData(MoviePresenter.java:107)

当我使用默认的非空值初始化 movieData 时,问题已解决:

Call<MovieJsonData> movieData = null;

更改为 ->

Call<MovieJsonData> movieData = trendingService.getTrendingMovies(API_KEY);