You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从AsyncTaskLoader传递额外变量?TMDB电影搜索应用问题

解决AsyncTaskLoader传递分页参数到MainActivity的问题

没问题,这个场景很常见,核心思路就是把电影列表和分页相关参数封装到一个自定义类中,替代原来只返回ArrayList<Movie>的方式,这样就能一次性传递所有需要的数据了。下面是具体的实现步骤:


步骤1:创建封装类MovieSearchResult

这个类用来统一存放API返回的所有关键信息,包括电影列表、总结果数、总页数、当前页码:

public class MovieSearchResult {
    private ArrayList<Movie> movies;
    private int totalResults;
    private int totalPages;
    private int currentPage;

    // 构造方法
    public MovieSearchResult(ArrayList<Movie> movies, int totalResults, int totalPages, int currentPage) {
        this.movies = movies;
        this.totalResults = totalResults;
        this.totalPages = totalPages;
        this.currentPage = currentPage;
    }

    // Getter方法,按需获取数据
    public ArrayList<Movie> getMovies() {
        return movies;
    }

    public int getTotalResults() {
        return totalResults;
    }

    public int getTotalPages() {
        return totalPages;
    }

    public int getCurrentPage() {
        return currentPage;
    }
}

步骤2:修改MovieAsyncTaskLoader的泛型和返回逻辑

把Loader的泛型从ArrayList<Movie>改成MovieSearchResult,并在loadInBackground中解析所有分页参数,封装后返回:

// 修改泛型为MovieSearchResult
public class MovieAsyncTaskLoader extends AsyncTaskLoader<MovieSearchResult> { 
    private MovieSearchResult searchResult; 
    private boolean hasResult = false; 
    private String keyword; 

    public MovieAsyncTaskLoader(final Context context, String keyword) { 
        super(context); 
        onContentChanged(); 
        this.keyword = keyword; 
    } 

    @Override 
    protected void onStartLoading() { 
        if (takeContentChanged()) forceLoad(); 
        else if (hasResult) deliverResult(searchResult); 
    } 

    @Override 
    public void deliverResult(final MovieSearchResult data) { 
        searchResult = data; 
        hasResult = true; 
        super.deliverResult(data); 
    } 

    @Override 
    protected void onReset() { 
        super.onReset(); 
        onStopLoading(); 
        if (hasResult) { 
            onReleaseResources(searchResult); 
            searchResult = null; 
            hasResult = false; 
        } 
    } 

    private void onReleaseResources(MovieSearchResult searchResult) { } 

    private static final String API_KEY = "323ee6e4b1621c63xxxxxxxxxxxxxxxx"; 

    @Override 
    public MovieSearchResult loadInBackground() { 
        SyncHttpClient client = new SyncHttpClient(); 
        final ArrayList<Movie> movies = new ArrayList<>(); 
        // 初始化分页参数,避免空指针
        int totalResults = 0;
        int totalPages = 0;
        int currentPage = 0;

        String url = "https://api.themoviedb.org/3/search/movie?api_key=" + API_KEY + "&language=en-US&query=" + keyword ; 
        client.get( url, new AsyncHttpResponseHandler() { 
            @Override 
            public void onStart() { 
                super.onStart(); 
                setUseSynchronousMode(true); 
            } 

            @Override 
            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { 
                try { 
                    String result = new String(responseBody); 
                    JSONObject responseObject = new JSONObject(result); 
                    // 解析分页参数
                    totalResults = responseObject.getInt("total_results"); 
                    totalPages = responseObject.getInt("total_pages"); 
                    currentPage = responseObject.getInt("page"); 

                    JSONArray list = responseObject.getJSONArray("results"); 
                    for (int i = 0 ; i < list.length() ; i++){ 
                        JSONObject movieitem = list.getJSONObject(i); 
                        Movie movie = new Movie(movieitem); 
                        movies.add(movie); 
                    } 
                }catch (Exception e){ 
                    e.printStackTrace(); 
                } 
            } 

            @Override 
            public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { 
                // 请求失败时重置参数,避免后续空指针
                totalResults = 0;
                totalPages = 0;
                currentPage = 0;
            } 
        }); 

        // 返回封装好的完整结果
        return new MovieSearchResult(movies, totalResults, totalPages, currentPage); 
    } 
}

步骤3:修改MainActivity的Loader回调实现

把LoaderCallbacks的泛型改成MovieSearchResult,并在onLoadFinished中获取总结果数更新TextView:

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<MovieSearchResult> { 
    MovieListAdapter adapter; 
    ListView movielist; 
    EditText etKeyword; 
    Button btSearch; 
    TextView tvFound; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 

        adapter = new MovieListAdapter(this); 
        adapter.notifyDataSetChanged(); 

        movielist = findViewById(R.id.lvMovie); 
        movielist.setAdapter(adapter); 

        etKeyword = findViewById(R.id.etKeyword); 
        btSearch = findViewById(R.id.btSearch); 
        tvFound = findViewById(R.id.tvFound); 

        btSearch.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View view) { 
                String keyword = etKeyword.getText().toString(); 
                if (TextUtils.isEmpty(keyword)) return; 

                Bundle bundle = new Bundle(); 
                bundle.putString("keyword", keyword); 
                getLoaderManager().restartLoader(0, bundle, MainActivity.this); 
            } 
        }); 

        // 初始化加载(如果需要默认搜索)
        String initialKeyword = etKeyword.getText().toString(); 
        Bundle initialBundle = new Bundle(); 
        initialBundle.putString("keyword", initialKeyword); 
        getLoaderManager().restartLoader(0, initialBundle, this); 
    } 

    @Override 
    public Loader<MovieSearchResult> onCreateLoader(int i, Bundle bundle) { 
        String keyword = ""; 
        if( bundle != null) { 
            keyword = bundle.getString("keyword"); 
        } 
        return new MovieAsyncTaskLoader(this, keyword ); 
    } 

    @Override 
    public void onLoadFinished(Loader<MovieSearchResult> loader, MovieSearchResult result) { 
        // 更新电影列表
        adapter.setDatamovie(result.getMovies()); 
        // 更新总结果数到TextView
        tvFound.setText("Found " + result.getTotalResults() + " movies"); 
        // 如果需要实现分页按钮,这里也可以拿到totalPages和currentPage做逻辑处理
    } 

    @Override 
    public void onLoaderReset(Loader<MovieSearchResult> loader) { 
        adapter.setDatamovie(null); 
        tvFound.setText(""); // 重置文本
    } 
}

额外说明

  • 这种封装方式扩展性很强,后续如果需要传递更多API返回的参数,只需要在MovieSearchResult中添加对应字段即可。
  • 在请求失败的回调中初始化分页参数,能有效避免空指针异常。
  • 现在你不仅能显示总结果数,还可以利用totalPages和currentPage快速实现分页切换功能(比如上一页/下一页按钮)。

内容的提问来源于stack exchange,提问作者Sofyan Thayf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:16:03