I make a movie search application using TMDB API, but TMDB always give results in pages with 20 results each page, so I need to arrange interface for page selection.
I'm using AsyncTaskLoader to make asynchronous API request, but I don't know how to send variabels out from background process other than return value.
Here is my AsyncTaskLoader class:
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;
}
}
and this is my MainActivity class:
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);
}
}
The movielist
ListView works fine to show the result, but I want to put the total_results
in tvFound
TextView
Here is my Movie POJO class:
public class Movie implements Parcelable {
private Integer voteCount;
private Integer id;
private Boolean video;
private Double voteAverage;
private String title;
private Double popularity;
private String posterPath;
private String originalLanguage;
private String originalTitle;
private List<Integer> genreIds = null;
private String backdropPath;
private Boolean adult;
private String overview;
private String releaseDate;
public Movie(JSONObject movieobject){
try {
Integer votecount = movieobject.getInt("vote_count");
Integer id = movieobject.getInt("id");
Boolean video = movieobject.getBoolean("video");
Double voteaverage = movieobject.getDouble("vote_average");
String title = movieobject.getString("title");
Double popularity = movieobject.getDouble("popularity");
String posterpath = movieobject.getString("poster_path");
String originallanguage = movieobject.getString("original_language");
String originaltitle = movieobject.getString("original_title");
List<Integer> genreid = (List<Integer>) movieobject.optJSONArray("genre_id");
String backdroppath = movieobject.getString("backdrop_path");
Boolean adult = movieobject.getBoolean("adult");
String overview = movieobject.getString("overview");
String releasedate = movieobject.getString("release_date");
this.voteCount = votecount;
this.id = id;
this.video = video;
this.voteAverage = voteaverage;
this.title = title;
this.popularity = popularity;
this.posterPath = posterpath;
this.originalLanguage = originallanguage;
this.originalTitle = originaltitle;
this.genreIds = genreid;
this.backdropPath = backdroppath;
this.adult = adult;
this.overview = overview;
this.releaseDate = releasedate;
} catch (JSONException e) {
e.printStackTrace();
}
}
public Integer getVoteCount() {
return voteCount;
}
public void setVoteCount(Integer voteCount) {
this.voteCount = voteCount;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Boolean getVideo() {
return video;
}
public void setVideo(Boolean video) {
this.video = video;
}
public Double getVoteAverage() {
return voteAverage;
}
public void setVoteAverage(Double voteAverage) {
this.voteAverage = voteAverage;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Double getPopularity() {
return popularity;
}
public void setPopularity(Double popularity) {
this.popularity = popularity;
}
public String getPosterPath() {
return posterPath;
}
public void setPosterPath(String posterPath) {
this.posterPath = posterPath;
}
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 getBackdropPath() {
return backdropPath;
}
public void setBackdropPath(String backdropPath) {
this.backdropPath = backdropPath;
}
public Boolean getAdult() {
return adult;
}
public void setAdult(Boolean adult) {
this.adult = adult;
}
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;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(this.voteCount);
dest.writeValue(this.id);
dest.writeValue(this.video);
dest.writeValue(this.voteAverage);
dest.writeString(this.title);
dest.writeValue(this.popularity);
dest.writeString(this.posterPath);
dest.writeString(this.originalLanguage);
dest.writeString(this.originalTitle);
dest.writeList(this.genreIds);
dest.writeString(this.backdropPath);
dest.writeValue(this.adult);
dest.writeString(this.overview);
dest.writeString(this.releaseDate);
}
protected Movie(Parcel in) {
this.voteCount = (Integer) in.readValue(Integer.class.getClassLoader());
this.id = (Integer) in.readValue(Integer.class.getClassLoader());
this.video = (Boolean) in.readValue(Boolean.class.getClassLoader());
this.voteAverage = (Double) in.readValue(Double.class.getClassLoader());
this.title = in.readString();
this.popularity = (Double) in.readValue(Double.class.getClassLoader());
this.posterPath = in.readString();
this.originalLanguage = in.readString();
this.originalTitle = in.readString();
this.genreIds = new ArrayList<Integer>();
in.readList(this.genreIds, Integer.class.getClassLoader());
this.backdropPath = in.readString();
this.adult = (Boolean) in.readValue(Boolean.class.getClassLoader());
this.overview = in.readString();
this.releaseDate = in.readString();
}
public static final Parcelable.Creator<Movie> CREATOR = new Parcelable.Creator<Movie>() {
@Override
public Movie createFromParcel(Parcel source) {
return new Movie(source);
}
@Override
public Movie[] newArray(int size) {
return new Movie[size];
}
};
}
and this is results example from TMDB API request:
{"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"},
...
]
}
Thank You in advanced
You can create an interface to listen when you finish loading the movies list, and make MainActivity
implement this interface.
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
code:
//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
}
......
......
}