我是使用TMDb API来构建项目应用程序。每次api通话都会给我20部电影,所以通常应用程序在启动时只显示20部电影海报。当用户向下滚动网格视图时,我添加了此代码以使用& page =查询获取另外20部电影。
gridView.setOnScrollListener(onScrollListener());
private AbsListView.OnScrollListener onScrollListener() {
return new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
int threshold = 1;
int count = gridView.getCount();
if (scrollState == SCROLL_STATE_IDLE) {
if (gridView.getLastVisiblePosition() >= count - threshold && pageCount < 2) {
Log.v(LOG_TAG, "loading more data");
// Execute LoadMoreDataTask AsyncTask
updateMovies(sortBy, true);
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
}
};
}
但是这个解决方案非常糟糕。如果我向下滚动它会立即执行updateMovies(sortBy, true);
2-3次,跳页并使其无法读取。
此外,屏幕上显示的数据在每次刷新页面后都会被完全替换,例如,如果我在页面上看到数据= 1并向下滚动,那么我只看到第2页或第3页的数据,但原始数据是走了。
这是我的AsyncTask
public class FetchMoviesTask extends AsyncTask<String, Void, List<Movie>> {
private final String LOG_TAG = FetchMoviesTask.class.getSimpleName();
private final static String API_KEY = "480a9e79c0937c9f4e4a129fd0463f96";
@Override
protected List<Movie> doInBackground(String... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String jsonStr = null;
try {
final String BASE_URL = "http://api.themoviedb.org/3/movie";
final String API_KEY_PARAM = "api_key";
final String PAGE_PARAM = "page";
URL url;
if (params[1].equals("true")){
// if a bool is true
// then I intend to load an additional page
// (needed otherwise going back from detailAct loads a new increasing page
currentPage += 1;
pageCount++;
}else{
currentPage = 1;
}
if (params[0].equals(POPULARITY_DESC)){
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendPath("popular")
.appendQueryParameter(API_KEY_PARAM, API_KEY) // my own API key
.appendQueryParameter(PAGE_PARAM , Integer.toString(currentPage))
.build();
url = new URL(builtUri.toString());
}else if(params[0].equals(RATING_DESC)) {
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendPath("top_rated")
.appendQueryParameter(API_KEY_PARAM, API_KEY)// my own API key
.appendQueryParameter(PAGE_PARAM , Integer.toString(currentPage))
.build();
url = new URL(builtUri.toString());
}else {
Log.v(LOG_TAG, "Something went wrong with URI building :(");
url = new URL("ERROR URL");
}
Log.v(LOG_TAG, "URL BUILT: " + url);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
jsonStr = buffer.toString(); // finally parsed JSON string
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
try {
return getMoviesDataFromJson(jsonStr);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
// This will only happen if there was an error getting or parsing the forecast.
return null;
}
private List<Movie> getMoviesDataFromJson(String jsonStr) throws JSONException {
JSONObject movieJson = new JSONObject(jsonStr);
JSONArray movieArray = movieJson.getJSONArray("results");
List<Movie> results = new ArrayList<>();
for(int i = 0; i < movieArray.length(); i++) {
JSONObject movie = movieArray.getJSONObject(i);
Movie movieModel = new Movie(movie); // basically Movie has already the fields to fill (image,
// description, rating, etc) and this adds those values from the JSONObject
results.add(movieModel); // it does this one object at the time, for the lenght of the array
}
return results;
}
@Override
protected void onPostExecute(List<Movie> mv) {
if (mv != null) {
if (movieGridAdapter != null) {
movieGridAdapter.clear();
for (Movie movie : mv) {
movieGridAdapter.add(movie);
}
}
movies = new ArrayList<>();
movies.addAll(mv);
}
}
}