应用程序描述:此应用程序显示主要活动中的热门/顶级电影列表,这些电影是从themoviedb.org拍摄的电影海报。我可以收藏/取消收藏电影,并且收藏的电影ID,标题和张贴者路径保存在数据库中。 我可以单击“收藏夹”选项来显示我喜欢的电影。
问题:
当我通过在“收藏夹”列表中或受欢迎或排名最高的列表中单击其海报来取消收藏该电影时,“收藏夹”视图的确显示了正确的海报,但是通过点按“现在放在那个地方的海报。第二次单击,一切正常,或者我再次单击“收藏夹”选项。 日志显示我的JSONArray最爱JsonArray保持为空,直到我第二次单击海报或单击收藏夹选项。
代码:
MainActivity:
package com.example.android.popularmovies;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.android.popularmovies.Database.Contract;
import com.example.android.popularmovies.utilities.NetworkUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private final static String BASE_POSTER_URL = "http://image.tmdb.org/t/p/w500/";
private static String OPTION = "OPTION";
TextView mNoFavorites;
JSONArray favoriteJsonArray = new JSONArray();
int optionChosen;
private ProgressBar mProgessBar;
private TextView mErrorMessage;
private Button mRetry;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private URL url;
private ArrayList<String> posterList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.my_recycler_view);
mRecyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(this, 2);
mRecyclerView.setLayoutManager(mLayoutManager);
//mAdapter = new MainActivityAdapter(this, posterList, null);
//mRecyclerView.setAdapter(mAdapter);
mProgessBar = findViewById(R.id.progess_bar);
mErrorMessage = findViewById(R.id.error_message);
mRetry = findViewById(R.id.retry);
mNoFavorites = findViewById(R.id.no_favorites_yet);
favoriteJsonArray = new JSONArray();
tryToConnect(new View(this));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.preferences, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
try {
if (item.getItemId() == R.id.top_rated) {
mRecyclerView.setVisibility(View.VISIBLE);
mNoFavorites.setVisibility(View.INVISIBLE);
url = NetworkUtils.buildUrl("top_rated");
if (url != null) {
mErrorMessage.setVisibility(View.INVISIBLE);
mRetry.setVisibility(View.INVISIBLE);
new FetchMovies().execute(url, null, null);
}
optionChosen = 1;
}
if (item.getItemId() == R.id.most_popular) {
mRecyclerView.setVisibility(View.VISIBLE);
mNoFavorites.setVisibility(View.INVISIBLE);
url = NetworkUtils.buildUrl("most_popular");
if (url != null) {
mErrorMessage.setVisibility(View.INVISIBLE);
mRetry.setVisibility(View.INVISIBLE);
new FetchMovies().execute(url, null, null);
}
optionChosen = 2;
}
if (item.getItemId() == R.id.favorites) {
optionFavorites();
optionChosen = 3;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (java.lang.NullPointerException e) {
e.printStackTrace();
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
if (optionChosen == 3)
optionFavorites();
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(OPTION, optionChosen);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
optionChosen = savedInstanceState.getInt(OPTION);
}
private void optionFavorites() {
try {
String[] projection = {"movie_id", "favorite_poster_path"};
Cursor cursor = getContentResolver().query(
Contract.FavoriteMovieDatabase.CONTENT_URI,
projection,
null,
null,
null
);
ArrayList<String> posterPathArrayList = new ArrayList<>();
ArrayList<URL> urlArrayList = new ArrayList<>();
if (cursor != null && cursor.moveToFirst()) {
do {
String posterPath = cursor.getString(cursor.getColumnIndex(Contract.FavoriteMovieDatabase.FAVORITE_POSTER_PATH));
posterPathArrayList.add(BASE_POSTER_URL + posterPath);
int movieId = cursor.getInt(cursor.getColumnIndex("movie_id"));
URL favoriteURL = NetworkUtils.buildUrl("favorites", movieId);
urlArrayList.add(favoriteURL);
} while (cursor.moveToNext());
new FetchFavorites().execute(urlArrayList);
mAdapter = new MainActivityAdapter(MainActivity.this, posterPathArrayList, favoriteJsonArray);
mRecyclerView.setAdapter(mAdapter);
} else {
mRecyclerView.setVisibility(View.INVISIBLE);
mNoFavorites.setVisibility(View.VISIBLE);
}
} catch (java.lang.NullPointerException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
private void noConnection() {
mErrorMessage.setText(R.string.no_connection);
mErrorMessage.setVisibility(View.VISIBLE);
mRetry.setText(R.string.retry);
mRetry.setVisibility(View.VISIBLE);
}
public void tryToConnect(View v) {
try {
url = NetworkUtils.buildUrl("most_popular");
} catch (MalformedURLException e) {
e.printStackTrace();
}
if (url != null) {
mErrorMessage.setVisibility(View.INVISIBLE);
mRetry.setVisibility(View.INVISIBLE);
new FetchMovies().execute(url, null, null);
}
}
private class FetchMovies extends AsyncTask<URL, Void, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgessBar.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(URL... params) {
URL searchUrl = params[0];
String searchResults = null;
try {
searchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);
} catch (IOException e) {
e.printStackTrace();
}
return searchResults;
}
@Override
protected void onPostExecute(String searchResults) {
mProgessBar.setVisibility(View.INVISIBLE);
try {
posterList = new ArrayList<>();
if (searchResults != null && !searchResults.equals("")) {
JSONObject jsonObject = new JSONObject(searchResults);
JSONArray pageOne = jsonObject.getJSONArray("results");
int length = pageOne.length();
for (int i = 0; i < length; i++) {
JSONObject result = pageOne.getJSONObject(i);
String posterPath = BASE_POSTER_URL + result.getString("poster_path");
posterList.add(posterPath);
}
mAdapter = new MainActivityAdapter(MainActivity.this, posterList, pageOne);
mRecyclerView.setAdapter(mAdapter);
} else noConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class FetchFavorites extends AsyncTask<ArrayList<URL>, Void, ArrayList<String>> {
/* @Override
protected void onPreExecute() {
super.onPreExecute();
mProgessBar.setVisibility(View.VISIBLE);
}*/
@Override
protected ArrayList<String> doInBackground(ArrayList<URL>... params) {
ArrayList<URL> arrayList = params[0];
ArrayList<String> searchResultsList = new ArrayList<>();
String searchResults;
URL searchUrl;
for (int i = 0; i < arrayList.size(); i++) {
searchUrl = arrayList.get(i);
try {
searchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);
searchResultsList.add(searchResults);
} catch (IOException e) {
e.printStackTrace();
}
}
return searchResultsList;
}
@Override
protected void onPostExecute(ArrayList<String> searchResultsList) {
mProgessBar.setVisibility(View.INVISIBLE);
favoriteJsonArray = new JSONArray();
try {
for (int i = 0; i < searchResultsList.size(); i++) {
String searchResults = searchResultsList.get(i);
if (searchResults != null && !searchResults.equals(""))
favoriteJsonArray.put(new JSONObject(searchResults));
else
noConnection();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
MainActivityAdapter:
package com.example.android.popularmovies;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class MainActivityAdapter extends RecyclerView.Adapter<MainActivityAdapter.ViewHolder> {
private final ArrayList<String> mPosterList;
private final Context mContext;
private JSONArray mJsonArray;
// Provide a suitable mConstructorInvoked (depends on the kind of dataset)
MainActivityAdapter(Context context, ArrayList<String> posterList, JSONArray jsonArray) {
this.mPosterList = posterList;
this.mContext = context;
this.mJsonArray = jsonArray;
}
// Create new views (invoked by the layout manager)
@NonNull
@Override
public MainActivityAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
int viewType) {
// create a new view
ImageView v = (ImageView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_image_view, parent, false);
return new ViewHolder(v);
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
Picasso.with(mContext).load(mPosterList.get(position)).into(holder.mImageView);
holder.mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
JSONObject jsonObject;
jsonObject = mJsonArray.getJSONObject(position);
Intent intent = new Intent(mContext, MovieDetails.class);
Intent reviewIntent = new Intent(mContext, MovieReviews.class);
intent.putExtra("title", jsonObject.getString("title"));
intent.putExtra("poster", jsonObject.getString("poster_path"));
intent.putExtra("overview", jsonObject.getString("overview"));
intent.putExtra("userRating", jsonObject.getString("vote_average"));
intent.putExtra("releaseDate", jsonObject.getString("release_date"));
intent.putExtra("movieId", jsonObject.getInt("id"));
reviewIntent.putExtra("movieId", jsonObject.getInt("id"));
mContext.startActivity(intent);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mPosterList.size();
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
final ImageView mImageView;
ViewHolder(ImageView v) {
super(v);
mImageView = v;
}
}
}
电影详细信息:
package com.example.android.popularmovies;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.example.android.popularmovies.Database.Contract;
import com.example.android.popularmovies.utilities.NetworkUtils;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
public class MovieDetails extends AppCompatActivity {
private String title;
private long position;
private ToggleButton favoriteButton;
private ProgressBar mProgessBar;
private MovieTrailersAdapter mAdapter;
private ArrayList<String> mTrailerList = new ArrayList<>();
private int mMovieId;
private RecyclerView mRecyclerView;
private TextView mErrorMessage;
private Button mRetry;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.read_reviews, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.read_reviews) {
Intent reviewIntent = new Intent(this, MovieReviews.class);
reviewIntent.putExtra("movieId", mMovieId);
startActivity(reviewIntent);
}
return super.onOptionsItemSelected(item);
}
private void noConnection() {
mErrorMessage.setText(R.string.no_connection);
mErrorMessage.setVisibility(View.VISIBLE);
mRetry.setText(R.string.retry);
mRetry.setVisibility(View.VISIBLE);
}
public void tryToConnect(View v) {
try {
URL movieTrailerUrl = NetworkUtils.buildUrl("trailers", mMovieId);
mErrorMessage.setVisibility(View.INVISIBLE);
mRetry.setVisibility(View.INVISIBLE);
new FetchMovieTrailers().execute(
movieTrailerUrl,
null,
null);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_details);
try {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} catch (NullPointerException e) {
e.printStackTrace();
}
mRecyclerView = findViewById(R.id.trailer_recycler_view);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new MovieTrailersAdapter(this, mTrailerList);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setAdapter(mAdapter);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
mProgessBar = findViewById(R.id.progess_bar_trailers);
mErrorMessage = findViewById(R.id.error_message_trailers);
mRetry = findViewById(R.id.retry_trailers);
Intent intent = getIntent();
mMovieId = intent.getIntExtra("movieId", 0);
title = intent.getStringExtra("title");
final String poster = intent.getStringExtra("poster");
String overview = intent.getStringExtra("overview");
String userRating = intent.getStringExtra("userRating");
String releaseDate = intent.getStringExtra("releaseDate");
TextView titleTV = findViewById(R.id.title);
titleTV.setText(title);
TextView overviewTV = findViewById(R.id.overview);
overviewTV.setText(overview);
TextView userRatingTV = findViewById(R.id.user_rating);
String rating = userRating + getString(R.string.out_of_ten);
userRatingTV.setText(rating);
TextView releaseDateTV = findViewById(R.id.release_date);
releaseDateTV.setText(releaseDate.substring(0, 4)); //Returns year of release
ImageView imageView = findViewById(R.id.poster);
String POSTER_PATH = "http://image.tmdb.org/t/p/w500/";
Picasso.with(this).load(POSTER_PATH + poster).into(imageView);
tryToConnect(new View(this));
favoriteButton = findViewById(R.id.mark_as_favorite);
boolean isFavorite = isMovieFavorite();
if (!isFavorite)
favoriteButton.setChecked(false);
else
favoriteButton.setChecked(true);
favoriteButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
boolean isFavorite = isMovieFavorite();
if (!isFavorite) {
ContentValues contentValues = new ContentValues();
contentValues.put(Contract.FavoriteMovieDatabase.COLUMN_NAME_TITLE, title);
contentValues.put(Contract.FavoriteMovieDatabase.MOVIE_ID, mMovieId);
contentValues.put(Contract.FavoriteMovieDatabase.FAVORITE_POSTER_PATH, poster);
Uri uri = getContentResolver().insert(Contract.FavoriteMovieDatabase.CONTENT_URI, contentValues);
if (uri != null)
Toast.makeText(getBaseContext(), title + " added to favorites", Toast.LENGTH_SHORT).show();
favoriteButton.setChecked(true);
} else {
Uri uri = Contract.FavoriteMovieDatabase.CONTENT_URI;
uri = uri.buildUpon().appendPath(String.valueOf(position)).build();
int result = getContentResolver().delete(uri, null, null);
if (result > 0)
Toast.makeText(getBaseContext(), title + " " + "removed", Toast.LENGTH_LONG).show();
else
Toast.makeText(getBaseContext(), title + " " + "not a favorite", Toast.LENGTH_LONG).show();
favoriteButton.setChecked(false);
}
}
}
);
}
private boolean isMovieFavorite() {
String[] projection = {"_id", "movie_id"};
Cursor cursor = getContentResolver().query(
Contract.FavoriteMovieDatabase.CONTENT_URI,
projection,
null,
null,
null
);
if (cursor != null && cursor.moveToFirst())
do {
if (cursor.getInt(cursor.getColumnIndex(Contract.FavoriteMovieDatabase.MOVIE_ID)) == mMovieId) {
position = cursor.getLong(cursor.getColumnIndex("_id"));
return true;
}
} while (cursor.moveToNext());
return false;
}
@Override
public boolean onSupportNavigateUp() {
finish();
return true;
}
private class FetchMovieTrailers extends AsyncTask<URL, Void, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgessBar.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(URL... params) {
URL searchUrl = params[0];
String searchResults = null;
try {
searchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);
} catch (IOException e) {
e.printStackTrace();
}
return searchResults;
}
@Override
protected void onPostExecute(String searchResults) {
mProgessBar.setVisibility(View.INVISIBLE);
try {
mTrailerList = new ArrayList<>();
if (searchResults != null && !searchResults.equals("")) {
JSONObject jsonObject = new JSONObject(searchResults);
JSONArray pageOne = jsonObject.getJSONArray("results");
int length = pageOne.length();
for (int i = 0; i < length; i++) {
JSONObject result = pageOne.getJSONObject(i);
String movieTrailerKey = result.getString("key");
mTrailerList.add(movieTrailerKey);
}
mAdapter = new MovieTrailersAdapter(MovieDetails.this, mTrailerList);
mRecyclerView.setAdapter(mAdapter);
} else
noConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
编辑:对该问题的进一步说明: 当我单击“收藏夹”电影收藏集中的电影海报(存储在数据库中),然后单击“从收藏夹中删除”,然后返回到“收藏夹”收藏中时,该电影的海报不会按预期显示。但是,单击前一个海报所在位置的电影海报仍会显示前一部电影的电影详细信息。