AsyncTask 不刷新 UI
AsyncTask not refreshing UI
我有一个应用程序,我在其中从 AsyncTask 中的 API 检索电影 posters。我需要显示 top_rated 和 热门 电影。因此,我的选项菜单中有 受欢迎 和 最高评价。打开应用程序时,它会通过 AsyncTask 加载 (20) 部热门电影。现在的问题是点击我的选项菜单中的流行或最高评分,它将新获取的 (20) post 人添加到 UI 上的 (20) 人中(使其成为 40 部电影现在)而不是清除屏幕上的那些并替换为新获取的 20 部电影 posters.
我试过在适配器上调用 notifyDataSetChanged()
。另外,我尝试为每个单击的选项调用一个新的 AsyncTask,但都没有用。我尝试了 this thread 上的选项,但无济于事。
这是我的代码:
package com.quwaysim.popularmovies.ui;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.quwaysim.popularmovies.MovieAdapter;
import com.quwaysim.popularmovies.R;
import com.quwaysim.popularmovies.model.MovieDetails;
import com.quwaysim.popularmovies.utils.NetworkUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
MovieAdapter mAdapter;
ArrayList<MovieDetails> mMovieList = new ArrayList<>();
ProgressBar mProgressBar;
String api = "popular";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressBar = findViewById(R.id.progressBar);
mRecyclerView = findViewById(R.id.movies_rv);
fetchMovies(api);
}
public void fetchMovies(String api) {
URL apiURL = NetworkUtils.buildUrl(api);
new FetchMovie().execute(apiURL);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.sort_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.popular:
Toast.makeText(this, "Popular", Toast.LENGTH_SHORT).show();
// Trying my options here
URL popular = NetworkUtils.buildUrl("popular");
new FetchMovie().execute(popular);
mAdapter.notifyDataSetChanged();
return true;
case R.id.top_rated:
Toast.makeText(this, "Top Rated", Toast.LENGTH_SHORT).show();
// Trying my options here
URL topRated = NetworkUtils.buildUrl("top_rated");
new FetchMovie().execute(topRated);
mAdapter.notifyDataSetChanged();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public class FetchMovie extends AsyncTask<URL, Void, String> {
private final String TAG = "FetchMovieAsyncTask";
private int mNoOfMovies;
@Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
super.onPreExecute();
}
@Override
protected String doInBackground(URL... urls) {
URL url = urls[0];
String movieResults = null;
try {
movieResults = NetworkUtils.getResponseFromUrl(url);
} catch (IOException e) {
Log.d(TAG, "doInBackground: " + e);
}
return movieResults;
}
@Override
protected void onPostExecute(String s) {
if (s != null && !s.equals("")) {
mProgressBar.setVisibility(View.INVISIBLE);
try {
JSONObject parsedMoviesJSON = new JSONObject(s);
JSONArray moviesArray = parsedMoviesJSON.getJSONArray("results");
mNoOfMovies = moviesArray.length();
moviesArray.getString(1);
for (int i = 0; i < mNoOfMovies; i++) {
MovieDetails mMovDetails = new MovieDetails();
String details = moviesArray.get(i).toString();
JSONObject detailsParsed = new JSONObject(details);
mMovDetails.setMoviePoster("http://image.tmdb.org/t/p/w185/"
+ detailsParsed.getString("poster_path"));
mMovieList.add(mMovDetails);
Log.d(TAG, "onPostExecute: forLoop" + mMovDetails.getMoviePoster());
}
} catch (JSONException e) {
Log.d(TAG, "onPostExecute: error => " + e);
e.printStackTrace();
}
Log.d("TAG", "onPostExecute: movieList" + mMovieList);
mAdapter = new MovieAdapter(mMovieList);
mRecyclerView.setLayoutManager(new GridLayoutManager(MainActivity.this, 2));
mRecyclerView.setAdapter(mAdapter);
Log.d(TAG, "onPostExecute: it's a success " + mNoOfMovies);
}
}
}
}
NetworkUtils class 仅用于打开连接和构建完整 api URL。我没有把它包括在这里,因为我想让这个 post 尽可能短。如果您需要什么,请告诉我。提前致谢。
是的,发生这种情况是因为您一直在使用相同的列表对象,您必须先创建一个新列表,然后再在 onPostExecute() 中使用它,然后添加:
mMovieList = new ArrayList<>();
在for循环的正上方,像这样:
//create a new list for each query
mMovieList = new ArrayList<>();
for (int i = 0; i < mNoOfMovies; i++) {
MovieDetails mMovDetails = new MovieDetails();
String details = moviesArray.get(i).toString();
....
....
....
祝你好运。
我有一个应用程序,我在其中从 AsyncTask 中的 API 检索电影 posters。我需要显示 top_rated 和 热门 电影。因此,我的选项菜单中有 受欢迎 和 最高评价。打开应用程序时,它会通过 AsyncTask 加载 (20) 部热门电影。现在的问题是点击我的选项菜单中的流行或最高评分,它将新获取的 (20) post 人添加到 UI 上的 (20) 人中(使其成为 40 部电影现在)而不是清除屏幕上的那些并替换为新获取的 20 部电影 posters.
我试过在适配器上调用 notifyDataSetChanged()
。另外,我尝试为每个单击的选项调用一个新的 AsyncTask,但都没有用。我尝试了 this thread 上的选项,但无济于事。
这是我的代码:
package com.quwaysim.popularmovies.ui;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.quwaysim.popularmovies.MovieAdapter;
import com.quwaysim.popularmovies.R;
import com.quwaysim.popularmovies.model.MovieDetails;
import com.quwaysim.popularmovies.utils.NetworkUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
MovieAdapter mAdapter;
ArrayList<MovieDetails> mMovieList = new ArrayList<>();
ProgressBar mProgressBar;
String api = "popular";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressBar = findViewById(R.id.progressBar);
mRecyclerView = findViewById(R.id.movies_rv);
fetchMovies(api);
}
public void fetchMovies(String api) {
URL apiURL = NetworkUtils.buildUrl(api);
new FetchMovie().execute(apiURL);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.sort_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.popular:
Toast.makeText(this, "Popular", Toast.LENGTH_SHORT).show();
// Trying my options here
URL popular = NetworkUtils.buildUrl("popular");
new FetchMovie().execute(popular);
mAdapter.notifyDataSetChanged();
return true;
case R.id.top_rated:
Toast.makeText(this, "Top Rated", Toast.LENGTH_SHORT).show();
// Trying my options here
URL topRated = NetworkUtils.buildUrl("top_rated");
new FetchMovie().execute(topRated);
mAdapter.notifyDataSetChanged();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public class FetchMovie extends AsyncTask<URL, Void, String> {
private final String TAG = "FetchMovieAsyncTask";
private int mNoOfMovies;
@Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
super.onPreExecute();
}
@Override
protected String doInBackground(URL... urls) {
URL url = urls[0];
String movieResults = null;
try {
movieResults = NetworkUtils.getResponseFromUrl(url);
} catch (IOException e) {
Log.d(TAG, "doInBackground: " + e);
}
return movieResults;
}
@Override
protected void onPostExecute(String s) {
if (s != null && !s.equals("")) {
mProgressBar.setVisibility(View.INVISIBLE);
try {
JSONObject parsedMoviesJSON = new JSONObject(s);
JSONArray moviesArray = parsedMoviesJSON.getJSONArray("results");
mNoOfMovies = moviesArray.length();
moviesArray.getString(1);
for (int i = 0; i < mNoOfMovies; i++) {
MovieDetails mMovDetails = new MovieDetails();
String details = moviesArray.get(i).toString();
JSONObject detailsParsed = new JSONObject(details);
mMovDetails.setMoviePoster("http://image.tmdb.org/t/p/w185/"
+ detailsParsed.getString("poster_path"));
mMovieList.add(mMovDetails);
Log.d(TAG, "onPostExecute: forLoop" + mMovDetails.getMoviePoster());
}
} catch (JSONException e) {
Log.d(TAG, "onPostExecute: error => " + e);
e.printStackTrace();
}
Log.d("TAG", "onPostExecute: movieList" + mMovieList);
mAdapter = new MovieAdapter(mMovieList);
mRecyclerView.setLayoutManager(new GridLayoutManager(MainActivity.this, 2));
mRecyclerView.setAdapter(mAdapter);
Log.d(TAG, "onPostExecute: it's a success " + mNoOfMovies);
}
}
}
}
NetworkUtils class 仅用于打开连接和构建完整 api URL。我没有把它包括在这里,因为我想让这个 post 尽可能短。如果您需要什么,请告诉我。提前致谢。
是的,发生这种情况是因为您一直在使用相同的列表对象,您必须先创建一个新列表,然后再在 onPostExecute() 中使用它,然后添加:
mMovieList = new ArrayList<>();
在for循环的正上方,像这样:
//create a new list for each query
mMovieList = new ArrayList<>();
for (int i = 0; i < mNoOfMovies; i++) {
MovieDetails mMovDetails = new MovieDetails();
String details = moviesArray.get(i).toString();
....
....
....
祝你好运。