Android 如何从AsyncTaskLoader传递变量

Android 如何从AsyncTaskLoader传递变量,android,asynctaskloader,Android,Asynctaskloader,我使用TMDB API制作了一个电影搜索应用程序,但TMDB总是在页面中给出结果,每页20个结果,所以我需要安排页面选择的界面 我使用AsyncTaskLoader发出异步API请求,但除了返回值之外,我不知道如何从后台进程发送变量 这是我的AsyncTaskLoader类: public class MovieAsyncTaskLoader extends AsyncTaskLoader<ArrayList<Movie>> { private ArrayList<

我使用TMDB API制作了一个电影搜索应用程序,但TMDB总是在页面中给出结果,每页20个结果,所以我需要安排页面选择的界面

我使用AsyncTaskLoader发出异步API请求,但除了返回值之外,我不知道如何从后台进程发送变量

这是我的AsyncTaskLoader类:

public class MovieAsyncTaskLoader extends AsyncTaskLoader<ArrayList<Movie>> {

private ArrayList<Movie> movies;
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(movies);
}

@Override
public void deliverResult(final ArrayList<Movie> data) {
    movies = data;
    hasResult = true;
    super.deliverResult(data);
}

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

private void onReleaseResources(ArrayList<Movie> movies) {

}


private static final String API_KEY = "323ee6e4b1621c63xxxxxxxxxxxxxxxx";

@Override
public ArrayList<Movie> loadInBackground() {

    SyncHttpClient client = new SyncHttpClient();
    final ArrayList<Movie> movies = new ArrayList<>();
    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);

                // how to passing these variabels out to MainActivity ??
                Integer total_results = responseObject.getInt("total_results");
                Integer total_pages = responseObject.getInt("total_pages");
                Integer page = 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) {

        }
    });

    return movies;
  }
}
public class MainActivity extends AppCompatActivity implements 
LoaderManager.LoaderCallbacks<ArrayList<Movie>> {

MovieListAdapter adapter;
ListView movielist;
EditText etKeyword;
Button btSearch;
TextView tvFound;

public Integer total_results;

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

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

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

    etKeyword = (EditText) findViewById(R.id.etKeyword);
    String keyword = etKeyword.getText().toString();

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


    btSearch = (Button) findViewById( R.id.btSearch );
    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);
        }
    });

    tvFound = (TextView) findViewById(R.id.tvFound);

}

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

@Override
public void onLoadFinished(Loader<ArrayList<Movie>> loader, ArrayList<Movie> movies) {
    adapter.setDatamovie( movies );
}

@Override
public void onLoaderReset(Loader<ArrayList<Movie>> loader) {
    adapter.setDatamovie(null);
}
}
这是TMDB API请求的结果示例:

{"page":1,
 "total_results":14,
 "total_pages":1,
 "results":[
        {"vote_count":7143,
         "id":20352,
         "video":false,
         "vote_average":7.1,
         "title":"Despicable Me",
         "popularity":41.730844,
         "poster_path":"\/4zHJhBSY4kNZXfhTlmy2TzXD51M.jpg",
         "original_language":"en",
         "original_title":"Despicable Me",
         "genre_ids":[16,10751],
         "backdrop_path":"\/yo1ef57MEPkEE4BDZKTZGH9uDcX.jpg",
         "adult":false,
         "overview":"Villainous Gru lives up to ... <deleted> .",
         "release_date":"2010-07-08"},

        {"vote_count":5254,
         "id":93456,
         "video":false,
         "vote_average":7,
         "title":"Despicable Me 2",
         "popularity":56.02126,
         "poster_path":"\/kQrYyZQHkwkUg2KlUDyvymj9FAp.jpg",
         "original_language":"en",
         "original_title":"Despicable Me 2",
         "genre_ids":[16,35,10751],
         "backdrop_path":"\/rmgxcw8tGTmdhsWqdjGBS9uI1tO.jpg",
         "adult":false,
         "overview":"Gru is recruited by the Anti-Villain League to ... <deleted>.",
         "release_date":"2013-06-25"},
       ...
    ]
}
{“页面”:1,
“总结果”:14,
“总页数”:1,
“结果”:[
{“计票”:7143,
“id”:20352,
“视频”:假,
“平均投票数”:7.1,
“头衔”:“卑鄙的我”,
“受欢迎程度”:41.730844,
“海报路径”:“\/4zHJhBSY4kNZXfhTlmy2TzXD51M.jpg”,
“原始语言”:“en”,
“原始标题”:“卑鄙的我”,
“类型识别码”:[1610751],
“背景路径”:“\/yo1ef57MEPkEE4BDZKTZGH9uDcX.jpg”,
“成人”:假,
“概述”:“邪恶的格鲁人不辜负……”,
“发布日期”:“2010-07-08”},
{“计票”:5254,
“id”:93456,
“视频”:假,
“平均投票数”:7,
“头衔”:“卑鄙的我2”,
“人气”:56.02126,
“海报路径”:“\/KQRYYZQHKWKUG2KLUDYMJ9FAP.jpg”,
“原始语言”:“en”,
“原始标题”:“卑鄙的我2”,
“类型识别码”:[16,3510751],
“背景路径”:“\/rmgxcw8tGTmdhsWqdjGBS9uI1tO.jpg”,
“成人”:假,
“概述”:“Gru被反恶棍联盟招募到….”,
“发布日期”:“2013-06-25”},
...
]
}

在advanced中感谢您

您可以创建一个界面,在加载完电影列表后收听,并使
MainActivity
实现此界面

public class MovieAsyncTaskLoader extends AsyncTaskLoader<ArrayList<Movie>> {

private ArrayList<Movie> movies;
private boolean hasResult = false;
private String keyword;

private MoviesLoadingListener listener; //MainActivity

public MovieAsyncTaskLoader(final Context context, String keyword, MoviesLoadingListener listener) {
    super(context);

    onContentChanged();
    this.keyword = keyword;
    this.listener = listener; //set MainActivity as the listener
}

 .....
 .....

@Override
public ArrayList<Movie> loadInBackground() {

    SyncHttpClient client = new SyncHttpClient();
    final ArrayList<Movie> movies = new ArrayList<>();
    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);

                // how to passing these variabels out to MainActivity ??
                Integer total_results = responseObject.getInt("total_results");
                Integer total_pages = responseObject.getInt("total_pages");
                Integer page = responseObject.getInt("page");

                //here you pass the three integers to MainActivity
                listener.onMoviesLoaded(total_results, total_pages, 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) {

        }
    });

return movies;
  }

    //This is the interface that MainActivity will implement
    public interface MoviesLoadingListener {
        void onMoviesLoaded(int total_results, int total_pages, int page);
    }
}

好的,我知道这不是你想听的,但我不会使用
AsyncTaskLoader
,因为它不适合httprequest,因为你会在代码中迷失方向。你能做的最好的事情就是花点时间看看这个由Square编写的库

这也避免了JSON转换会让你发疯。您可以使用GSON,这是一个伟大的工具,它也支持改装

我注意到的最后一件事是,您正在使用Parcel对对象进行序列化和反序列化。我建议您使用自动为您生成读写操作的Parceler


这些东西将帮助您的代码保持可读性和干净性。希望我能帮上点忙:)

谢谢你的回答,但我遇到了另一个问题,我尝试了这个:
@Override public void on movies loaded(int total_results,int total_pages,int page){this.tvfind.setText(“find”+String.valueOf(total_results)+“movies”)}
它显示了结果,但出现此警告消息时,android.view.ViewRootImpl$CalledFromErrorThreadException:只有创建视图层次结构的原始线程才能接触其视图。和程序停止运行在我将
tvFound.setText()
放入
Rununuithread(new Runnable(){})
Thank's后,它现在工作正常
public class MovieAsyncTaskLoader extends AsyncTaskLoader<ArrayList<Movie>> {

private ArrayList<Movie> movies;
private boolean hasResult = false;
private String keyword;

private MoviesLoadingListener listener; //MainActivity

public MovieAsyncTaskLoader(final Context context, String keyword, MoviesLoadingListener listener) {
    super(context);

    onContentChanged();
    this.keyword = keyword;
    this.listener = listener; //set MainActivity as the listener
}

 .....
 .....

@Override
public ArrayList<Movie> loadInBackground() {

    SyncHttpClient client = new SyncHttpClient();
    final ArrayList<Movie> movies = new ArrayList<>();
    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);

                // how to passing these variabels out to MainActivity ??
                Integer total_results = responseObject.getInt("total_results");
                Integer total_pages = responseObject.getInt("total_pages");
                Integer page = responseObject.getInt("page");

                //here you pass the three integers to MainActivity
                listener.onMoviesLoaded(total_results, total_pages, 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) {

        }
    });

return movies;
  }

    //This is the interface that MainActivity will implement
    public interface MoviesLoadingListener {
        void onMoviesLoaded(int total_results, int total_pages, int page);
    }
}
 //MainActivity implements the interface we created
public class MainActivity extends AppCompatActivity implements 
 LoaderManager.LoaderCallbacks<ArrayList<Movie>>,
 MovieAsyncTaskLoader.MoviesLoadingListener {

    ......
    ......

    @Override
    public Loader<ArrayList<Movie>> onCreateLoader(int i, Bundle bundle) {
        String keyword = "";
        if( bundle != null) {
            keyword = bundle.getString("keyword");
        }
        //here you pass the activity as the listener in the third parameter
        return new MovieAsyncTaskLoader(this, keyword, this );
    }

    ......
    ......

    @Override
    public void onMoviesLoaded(int total_results, int total_pages, int page) {
        //do whatever you need with the three integers here
    }    

    ......
    ......
}