One of the activities (Activity A) I have in the application displays a list of videos as you can see in the image:
The videos are stored in an ArrayList called videosList, when the user select a video the video is played using an embedded YouTube player in another activity B.
The problem is when the user goes back from activity B (The activity with the video player) to activity A (The activity with the list of videos) the variable videosList is null so the application stops running with error.
I tried to implement the
protected void onSaveInstanceState(Bundle savedInstanceState) and the
protected void onRestoreInstanceState(Bundle savedInstanceState) methods to save the activity state and some variables so when the user is back to Activity A the application can display the list of videos again, but when I try to gat the values I previously saved in onSaveInstanceState(Bundle savedInstanceState) in the public void onCreate(Bundle savedInstanceState) the savedInstanceStateis always NULL.
Here is my code:
public class VideosCatalogActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private Toolbar toolbar;
private GridView videosGrid;
private ArrayList<VideoEntity> videosList;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private FirebaseDatabase database;
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, " onCreate(Bundle) - Ini ");
super.onCreate(savedInstanceState);
// onSaveInstanceState();
setContentView(R.layout.videos_catalog_layout);
toolbar = (Toolbar) findViewById(R.id.app_bar);
setSupportActionBar(toolbar);
toolbar.setTitle(R.string.app_name);
toolbar.setTitleTextColor(getResources().getColor(R.color.com_facebook_button_background_color_focused));
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = mAuth.getCurrentUser();
}
};
database = FirebaseDatabase.getInstance();
Bundle bundle = getIntent().getExtras();
String actividad = bundle.getString("Activity");
if (actividad.equals("DocumentariesCategoriesActivity")) {
videosList = bundle.getParcelableArrayList("com.app.example.VideoEntity");
updateCatalog();
/*
String videoId = "";
if (!videosList.isEmpty() && !videosList.equals(null)) {
for (VideoEntity video : videosList) {
DatabaseReference mRef = database.getReference().child("Videos").child(video.getId());
mRef.setValue(video);
}
videosGrid = (GridView) findViewById(R.id.videosGrid);
MyGridViewAdapter adapter = new MyGridViewAdapter(this);
adapter.setVideosList(videosList);
videosGrid.setAdapter(adapter);
videosGrid.setOnItemClickListener(this);
} */
}
Log.d(TAG, " onCreate(Bundle) - Fi ");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.d(TAG, "onCreateOptionsMenu(Menu) - Ini");
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
Log.d(TAG, "onCreateOptionsMenu(Menu) - Fi");
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
Log.d(TAG, "onOptionItemSelected(MenuItem) - Ini");
switch (menuItem.getItemId()) {
case R.id.action_logout:
updateActivity(mAuth.getCurrentUser());
}
Log.d(TAG, "onOptionItemSelected(MenuItem) - Fi");
return true;
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d(TAG, " onItemClick(AdapterView<?>, View, int, long) - Ini ");
Intent intent = new Intent(getApplicationContext(), YoutubePlayerActivity.class);
intent.putExtra("VIDEO_ID", videosList.get(position).getId());
startActivity(intent);
Log.d(TAG, " onItemClick(AdapterView<?>, View, int, long) - Fi ");
}
protected void updateActivity(FirebaseUser user) {
Log.d(TAG, "updateActivity(FirebaseUser) - Ini");
mAuth.signOut();
Intent i = new Intent(VideosCatalogActivity.this, LoginActivity.class);
startActivity(i);
Log.d(TAG, "updateActivity(FirebaseUser) - Fi");
}
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
Log.d(TAG, "onSaveInstanceState(Bundle) - Ini");
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putParcelableArrayList("VIDEOS_LIST", videosList);
savedInstanceState.putAll(savedInstanceState);
Log.d(TAG, "onSaveInstanceState(Bundle) - Fi");
Log.i("","onSaveInstance is executed");
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Log.d(TAG, "onRestoreInstanceState(Bundle) - Ini");
super.onRestoreInstanceState(savedInstanceState);
videosList = savedInstanceState.getParcelableArrayList("VIDEOS_LIST");
updateCatalog();
Log.i("","onRestoreInstance is executed");
Log.d(TAG, "onRestoreInstanceState(Bundle) - Fi");
}
protected void updateCatalog() {
Log.d(TAG, "updateCatalog() - Ini");
String videoId = "";
for (VideoEntity video : videosList) {
DatabaseReference mRef = database.getReference().child("Videos").child(video.getId());
mRef.setValue(video);
}
videosGrid = (GridView) findViewById(R.id.videosGrid);
MyGridViewAdapter adapter = new MyGridViewAdapter(this);
adapter.setVideosList(videosList);
videosGrid.setAdapter(adapter);
videosGrid.setOnItemClickListener(this);
Log.d(TAG, "updateCatalog() - Fi");
}
}
Any idea how can i solve this problem please ?
Why dont you use a SingletonData class? that stores the ArrayList and when you need to reload the ArrayList you load it from the Singleton.
public class DataSingleton {
private static DataSingleton instance = new DataSingleton();
private DataSingleton(){ }
public static DataSingleton getInstance(){ return instance; }
public static void setIntances(DataSingleton instance){DataSingleton.instance = instance;}
private ArrayList<Videos> videosList;
public void setArrayVideos(ArrayList<Videos> videos){
videosList=videos;
}
public ArrayList<Videos> getArrayVideos(){
return videosList;
}
}
then you call the class in the activity A and set the ArrayList wherever you want.
DataSingleton.getInstance().setArrayVideos(videosList);
videosList= DataSingleton.getInstance().getArrayVideos();
Your onSaveInstanceState implementation must be like this
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
Log.d(TAG, "onSaveInstanceState(Bundle) - Ini");
if(savedInstanceState == null)
{
savedInstanceState = new Bundle();
}
savedInstanceState.putParcelableArrayList("VIDEOS_LIST", videosList);
Log.d(TAG, "onSaveInstanceState(Bundle) - Fi");
Log.i("","onSaveInstance is executed");
super.onSaveInstanceState(savedInstanceState);
}
Related
I have this code. It displays two recycler views and wants to store their scroll positions for the rotation purpose. So here is my code.
public class DetailActivity extends AppCompatActivity implements DetailViewInteface, TrailersAdapter.TrailersAdapterOnClickHandler {
public static final String IMAGE_URL = "http://image.tmdb.org/t/p/";
public static final String IMAGE_SIZE_185 = "w185";
private static final String TAG = "DetailActivity";
private static final String TRAILERS_LAYOUT = "DetailsActivity.trailer.layout";
private static final String REVIEWS_LAYOUT = "DetailsActivity.review.layout";
private Parcelable listState1;
private Parcelable listState2;
#BindView(R.id.movie_image)
ImageView movieImageTv;
String mImage;
#BindView(R.id.movie_title)
TextView movieTitleTv;
String mTitle;
#BindView(R.id.movie_rating)
TextView movieRatingTv;
double mRating;
#BindView(R.id.movie_date)
TextView movieDateTv;
String mReleaseDate;
#BindView(R.id.movie_overview)
TextView movieOverviewTv;
String mMovieOverview;
#BindView(R.id.recyclerview_trailers)
RecyclerView trailersRecyclerView;
TrailersAdapter trailersAdapter;
#BindView(R.id.recyclerview_reviews)
RecyclerView reviewsRecyclerView;
ReviewAdapter reviewAdapter;
int recyclerViewOrientation = LinearLayoutManager.VERTICAL;
private Parcelable mLayoutManagerSavedState;
DetailPresenter detailPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
ButterKnife.bind(this);
setMVP();
setUpViews();
detailPresenter.getMovieDetails();
detailPresenter.getMovieTrailers();
detailPresenter.getMovieReviews();
}
public void setMVP(){
detailPresenter = new DetailPresenter(this,this);
}
public void setUpViews(){
trailersRecyclerView.setLayoutManager(new LinearLayoutManager(this));
trailersRecyclerView.addItemDecoration(new MyDividerItemDecoration(this,recyclerViewOrientation,16));
reviewsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
reviewsRecyclerView.addItemDecoration(new MyDividerItemDecoration(this,recyclerViewOrientation,16));
}
#Override
public void dipsplayMovieDetails(Movie movie) {
//movieTitleTv.setText(movieTitle);
//movieDescriptionTv.setText(movieDesc);
mImage = movie.getPosterPath();
Picasso.with(this).load(IMAGE_URL + IMAGE_SIZE_185 + mImage).into(movieImageTv);
mTitle = movie.getTitle();
movieTitleTv.setText(mTitle);
mRating = movie.getVoteAverage();
movieRatingTv.setText("Rating: " + mRating);
mReleaseDate = movie.getReleaseDate();
movieDateTv.setText("Date: " + mReleaseDate);
mMovieOverview = movie.getOverview();
movieOverviewTv.setText(mMovieOverview);
}
#Override
public void dipsplayMovieTrailers(TrailersResponse trailersResponse) {
Log.d(TAG, "Trailers size: " + String.valueOf(trailersResponse.getTrailers().size()));
trailersAdapter = new TrailersAdapter(trailersResponse.getTrailers(),DetailActivity.this,this);
trailersRecyclerView.setAdapter(trailersAdapter);
}
#Override
public void displayMovieReviews(ReviewsResponse reviewsResponse) {
if(reviewsResponse != null) {
Log.d(TAG, String.valueOf("Reviews size: " + reviewsResponse.getReviews().size()));
reviewAdapter = new ReviewAdapter(reviewsResponse.getReviews());
reviewsRecyclerView.setAdapter(reviewAdapter);
}else{
Toast.makeText(DetailActivity.this,"No reviews found!",Toast.LENGTH_LONG).show();
}
}
#Override
public void displayError(String s) {
showToast(s);
}
#Override
public void showToast(String s) {
Toast.makeText(DetailActivity.this,s,Toast.LENGTH_LONG).show();
}
#Override
public void onClick(String trailerKey) {
Intent appIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:" + trailerKey));
Intent webIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.youtube.com/watch?v=" + trailerKey));
try {
startActivity(appIntent);
} catch (ActivityNotFoundException ex) {
startActivity(webIntent);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(REVIEWS_LAYOUT,reviewsRecyclerView.getLayoutManager().onSaveInstanceState());
outState.putParcelable(TRAILERS_LAYOUT,trailersRecyclerView.getLayoutManager().onSaveInstanceState());
}
}
I use the onSaveInstanceState method. But now I need to restore in the scroll positions of recyclerviews.
I am using the onRestoreInstanceState as below but nothing happens. The rotation gets me to the top of the screen.
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
savedInstanceState.getParcelable(REVIEWS_LAYOUT);
savedInstanceState.getParcelable(TRAILERS_LAYOUT);
}
So how can I fix that bug?
Thanks,
Theo.
void addOnScrollListener (RecyclerView.OnScrollListener listener)
This is a listener that will be notified of any changes in scroll state or position for a recycler view.
Refer to this answer for an example implementation.
For more on how to use it correctly.
I've been facing issues with my MoviesApp for a while now and I feel that I've exhausted all my knowledge on this; I am quite new with Android so bear with me :-)
MoviesApp is a simple movie listing app, in which the user can scroll through the list of films, see details for each one and save their favorites in an SQLite DB.
I use SharedPreference to sort movies based by popularity, rating and favorites (the only list saved in the database), but when I change through each one, the UI is not updating at all.
I am really stuck and honestly, I could do with another pair of eyes, because, even if the answer is staring me in the face, I wouldn't be able to see it 😫😫😫
I pasted the link to the project below:
https://drive.google.com/file/d/1SweLpwfo5RntXrbtLPP3N_xS1bVs32Ze/view?usp=sharing
Thank you!!
Update: I believe the problem would in the MainActivity class, where the RecyclerView Loader is declared - specifically in onLoadFinished().
#SuppressWarnings({"WeakerAccess", "unused", "CanBeFinal"})
public class MainActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks,
MovieAdapter.MovieDetailClickHandler, SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = MainActivity.class.getSimpleName();
public static final String MOVIE_ID = "movieId";
private final static String LIFECYCLE_CALLBACKS_LAYOUT_MANAGER_KEY = "KeyForLayoutManagerState";
Parcelable savedLayoutManagerState;
public RecyclerView movieListRV;
private GridLayoutManager gridLayoutManager =
new GridLayoutManager(this, 1);
Context context = this;
// Loader IDs for loading the main API and the poster API, respectively
private static final int ID_LOADER_LIST_MOVIES = 1;
private static final int ID_LOADER_CURSOR = 2;
// adapter
private MovieAdapter adapter;
// detect internet connection
NetworkDetection networkDetection;
// swipe to refresh
SwipeRefreshLayout swipeRefreshLayout;
// sortOption
String sortOption = null;
// movie projection
private final String[] projection = new String[]{
MoviesContract.MovieEntry.COLUMN_MOVIE_POSTER,
MoviesContract.MovieEntry.COLUMN_MOVIE_ID
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stetho.initializeWithDefaults(this);
Toolbar toolbar = findViewById(R.id.settings_activity_toolbar);
setSupportActionBar(toolbar);
toolbar.setTitleTextColor(Color.WHITE);
networkDetection = new NetworkDetection(this);
swipeRefreshLayout = findViewById(R.id.discover_swipe_refresh);
swipeRefreshLayout.setOnRefreshListener(MainActivity.this);
swipeRefreshLayout.setColorScheme(android.R.color.holo_red_dark);
movieListRV = findViewById(R.id.recycler_view_movies);
movieListRV.setLayoutManager(gridLayoutManager);
movieListRV.setHasFixedSize(true);
ViewTreeObserver viewTreeObserver = movieListRV.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
calculateSize();
}
});
adapter = new MovieAdapter(this, this);
movieListRV.setAdapter(adapter);
RecyclerViewItemDecorator itemDecorator = new RecyclerViewItemDecorator(context,
R.dimen.item_offset);
movieListRV.addItemDecoration(itemDecorator);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences
(context);
SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener = new
SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
adapter.deleteItemsInList();
onRefresh();
if (key.equals(getString(R.string.pref_sort_by_key))) {
initializeloader();
}
}
};
preferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
initializeloader();
}
private static final int sColumnWidth = 200;
private void calculateSize() {
int spanCount = (int) Math.floor(movieListRV.getWidth() / convertDPToPixels(sColumnWidth));
((GridLayoutManager) movieListRV.getLayoutManager()).setSpanCount(spanCount);
}
#SuppressWarnings("SameParameterValue")
private float convertDPToPixels(int dp) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float logicalDensity = metrics.density;
return dp * logicalDensity;
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(LIFECYCLE_CALLBACKS_LAYOUT_MANAGER_KEY, gridLayoutManager
.onSaveInstanceState());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
savedLayoutManagerState = savedInstanceState.getParcelable
(LIFECYCLE_CALLBACKS_LAYOUT_MANAGER_KEY);
movieListRV.getLayoutManager().onRestoreInstanceState(savedLayoutManagerState);
}
}
#Override
public Loader onCreateLoader(int id, Bundle args) {
adapter.deleteItemsInList();
String urlMovieActivity;
switch (id) {
case ID_LOADER_CURSOR:
return new CursorLoader(context, MoviesContract.MovieEntry.MOVIES_CONTENT_URI,
projection, null, null, null);
case ID_LOADER_LIST_MOVIES:
urlMovieActivity = NetworkUtils.buildUrlMovieActivity(context, sortOption);
return new MovieLoader(this, urlMovieActivity);
default:
return null;
}
}
#Override
public void onLoadFinished(Loader loader, Object data) {
adapter.deleteItemsInList();
TextView noMoviesMessage = findViewById(R.id.no_movies_found_tv);
switch (loader.getId()) {
case ID_LOADER_CURSOR:
adapter.InsertList(data);
break;
case ID_LOADER_LIST_MOVIES:
//noinspection unchecked
List<MovieItem> movieItems = (List<MovieItem>) data;
if (networkDetection.isConnected()) {
noMoviesMessage.setVisibility(View.GONE);
adapter.InsertList(movieItems);
movieListRV.getLayoutManager().onRestoreInstanceState(savedLayoutManagerState);
} else {
noMoviesMessage.setVisibility(View.VISIBLE);
}
break;
}
adapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(Loader loader) {
switch (loader.getId()) {
case ID_LOADER_CURSOR:
adapter.InsertList(null);
break;
case ID_LOADER_LIST_MOVIES:
adapter.InsertList(null);
break;
}
}
#Override
public void onPostResume(Loader loader) {
super.onPostResume();
getLoaderManager().initLoader(ID_LOADER_CURSOR, null, this);
}
#Override
public void onSelectedItem(int movieId) {
Intent goToDetailActivity = new Intent(this, DetailMovieActivity.class);
goToDetailActivity.putExtra(MOVIE_ID, movieId);
startActivity(goToDetailActivity);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_general, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
int id = menuItem.getItemId();
if (id == R.id.action_general_settings) {
Intent goToSetting = new Intent(this, SettingsActivity.class);
startActivity(goToSetting);
return true;
} else if (id == R.id.action_refresh) {
onRefresh();
}
return super.onOptionsItemSelected(menuItem);
}
/**
* Called when a swipe gesture triggers a refresh.
*/
#Override
public void onRefresh() {
adapter.deleteItemsInList();
swipeRefreshLayout.setRefreshing(false);
restartloader();
adapter.notifyDataSetChanged();
}
private void restartloader() {
adapter.deleteItemsInList();
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_favourite))) {
getLoaderManager().restartLoader(ID_LOADER_CURSOR, null, MainActivity
.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_popularity))) {
sortOption = NetworkUtils.MOST_POPULAR_PARAM;
getLoaderManager().restartLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_rating))) {
sortOption = NetworkUtils.TOP_RATED_PARAM;
getLoaderManager().restartLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
adapter.notifyDataSetChanged();
}
public void initializeloader() {
restartloader();
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_favourite))) {
getLoaderManager().initLoader(ID_LOADER_CURSOR, null, MainActivity
.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_popularity))) {
onRefresh();
sortOption = NetworkUtils.MOST_POPULAR_PARAM;
getLoaderManager().initLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
if (MoviePreferences.getSortByPreference(context).equals(getString(R.string
.pref_sort_by_rating))) {
onRefresh();
sortOption = NetworkUtils.TOP_RATED_PARAM;
getLoaderManager().initLoader(ID_LOADER_LIST_MOVIES, null,
MainActivity.this);
}
adapter.notifyDataSetChanged();
}
}
Here is my situation.
In this screen, I click the comments button.
The Comment activity opens and I type what I want.
The comment is added successfully in firebase and it takes me back in detail activity.
So far everything is great! Now let's add another comment. Now you see I get duplicate comments.
I hope you see that too. Now in the DetailActivity I have a method called queryFirebaseDb() and that method is called inside both onCreate() and onResume() methods. If I don't use the onResume() method the data will not be display after clicking the back button from the CommentActivity. You see where I am going now right? The question is how to avoid duplicate data after coming back from CommentActivity. Here is my code.
public class DetailActivity extends AppCompatActivity {
ArrayList<Comment> commentArrayList;
ImageView mImageView;
TextView mTitle;
TextView mDate;
TextView mDescription;
TextView mAuthor;
ToggleButton mFavBtn;
private TextView noCommentsTextView;
private TextView commentsTextView;
private ImageButton imageButton;
private FloatingActionButton mShareBtn;
private String newsTitle;
private String newsImage;
private String newsDate;
private String newsDescription;
private static String NEWS_SHARE_HASHTAG = "#EasyNewsApp";
private String date1;
private String date2;
private String newsUrl;
private String newsAuthor;
private Cursor favoriteCursor;
private DatabaseReference mDatabase;
private static Bundle bundle = new Bundle();
private Uri uri;
private RecyclerView mRecyclerView;
private DisplayCommentsAdapter displayCommentsAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent i = getIntent();
mAuthor = (TextView) findViewById(R.id.detail_author);
mImageView = (ImageView) findViewById(R.id.detail_image_view);
mTitle = (TextView) findViewById(R.id.detail_title);
mDate = (TextView) findViewById(R.id.detail_publish_date);
mDescription = (TextView) findViewById(R.id.detail_description);
noCommentsTextView = (TextView)findViewById(R.id.noCommentsTextView);
commentsTextView = (TextView)findViewById(R.id.commentsTextView);
mShareBtn = (FloatingActionButton) findViewById(R.id.share_floating_btn);
mFavBtn = (ToggleButton) findViewById(R.id.fav_news_btn);
imageButton = (ImageButton)findViewById(R.id.detail_comment_image_btn);
mRecyclerView = (RecyclerView)findViewById(R.id.recycler_comments);
LinearLayoutManager manager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));
commentArrayList = new ArrayList<>();
mDatabase = FirebaseDatabase.getInstance().getReference();
mFavBtn.setTextOn(null);
mFavBtn.setText(null);
mFavBtn.setTextOff(null);
newsAuthor = i.getStringExtra("author");
newsImage = i.getStringExtra("image");
newsTitle = i.getStringExtra("newsTitle");
newsDate = i.getStringExtra("date");
newsDescription = i.getStringExtra("description");
newsUrl = i.getStringExtra("url");
date1 = newsDate.substring(0, 10);
date2 = newsDate.substring(11, 19);
Picasso.with(this).load(newsImage)
.placeholder(R.drawable.ic_broken_image)
.into(mImageView);
mTitle.setText(newsTitle);
mAuthor.setText("Author: " + newsAuthor);
mDescription.setText(newsDescription);
mDate.setText(date2 + ", " + date1);
mShareBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent shareIntent = createShareNewsIntent();
startActivity(shareIntent);
}
});
imageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent commentIntent = new Intent(DetailActivity.this, CommentActivity.class);
commentIntent.putExtra("newsTitle",newsTitle);
startActivity(commentIntent);
}
});
/**
* Handling the add/remove news part. We check if the specific news article
* exists in favourite.db.
*/
favoriteCursor = getContentResolver().query(FavouriteContract.FavouriteEntry.CONTENT_URI,
null,
FavouriteContract.FavouriteEntry.COLUMN_NEWS_TITLE + "=?",
new String[]{newsTitle},
null);
/**
* If yes then set the toggle button to true
*/
if (favoriteCursor.getCount() > 0) {
try {
mFavBtn.setChecked(true);
} finally {
favoriteCursor.close();
}
}
/**
* Else click the toggle button to add the news article as favourite
*/
mFavBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, final boolean isChecked) {
/**
* If checked the add the news article as favourite.
*/
if (isChecked) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... voids) {
ContentValues contentValues = new ContentValues();
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_TITLE, newsTitle);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_AUTHOR, newsAuthor);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_DESCRIPTION, newsDescription);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_URL, newsUrl);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_URL_TO_IMAGE, newsImage);
contentValues.put(FavouriteContract.FavouriteEntry.COLUMN_NEWS_PUBLISHED_AT, newsDate);
//The actual insertion in the db.
uri = getContentResolver().insert(FavouriteContract.FavouriteEntry.CONTENT_URI, contentValues);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(DetailActivity.this, "Article with title: " + newsTitle + " was added", Toast.LENGTH_SHORT).show();
}
}.execute();
} else {
/**
* If you uncheck the toggle button then delete the news article from the favourite db.
*/
Uri newsTitleOfFavNews = FavouriteContract.FavouriteEntry.buildNewsUriWithTitle(newsTitle);
//String title = uri.getPathSegments().get(1);// Get the task ID from the URI path
getContentResolver().delete(
newsTitleOfFavNews,
null,
null);
Toast.makeText(DetailActivity.this, "News article deleted from favourites ", Toast.LENGTH_SHORT).show();
}
}
});
queryFirebaseDb();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.detail_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
if(item.getItemId() == R.id.detail_browser_btn){
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(newsUrl));
startActivity(browserIntent);
} if(item.getItemId() == android.R.id.home){
NavUtils.navigateUpFromSameTask(this);
return true;
}
return true;
}
private Intent createShareNewsIntent() {
Intent shareIntent = ShareCompat.IntentBuilder.from(this)
.setType("text/plain")
.setText(NEWS_SHARE_HASHTAG + "\n\n\n" + newsTitle
+ "\n\n\n" + newsDescription
+ "\n\n\n" + newsDate)
.getIntent();
return shareIntent;
}
#Override
protected void onStart() {
super.onStart();
//queryFirebaseDb();
}
#Override
protected void onRestart() {
super.onRestart();
queryFirebaseDb();
//displayCommentsAdapter.notifyDataSetChanged();
}
public void queryFirebaseDb(){
/**
* Querying the database to check if the specific article has comments.
*/
mDatabase = FirebaseDatabase.getInstance().getReference();
Query query = mDatabase.child("comments").orderByChild("newsTitle").equalTo(newsTitle);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot dataSnapshots : dataSnapshot.getChildren()){
Comment comment = dataSnapshots.getValue(Comment.class);
//mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userId);
commentArrayList.add(comment);
displayCommentsAdapter = new DisplayCommentsAdapter(this,commentArrayList);
mRecyclerView.setAdapter(displayCommentsAdapter);
displayCommentsAdapter.setCommentsData(commentArrayList);
//Log.d(LOG_TAG, String.valueOf(commentArrayList.size()));
}
noCommentsTextView.setVisibility(View.GONE);
//commentsTextView.setVisibility(View.VISIBLE);
}else{
//Toast.makeText(DisplayComments.this,"There are no comments posted",Toast.LENGTH_LONG).show();
noCommentsTextView.setVisibility(View.VISIBLE);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
/*
#Override
protected void onPause() {
super.onPause();
bundle.putBoolean("ToggleButtonState", mFavBtn.isChecked());
}
#Override
public void onResume() {
super.onResume();
mFavBtn.setChecked(bundle.getBoolean("ToggleButtonState",false));
}
*/
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mFavBtn.setChecked(savedInstanceState.getBoolean("ToggleButtonState",false));
savedInstanceState.putParcelableArrayList("newsList",commentArrayList);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("ToggleButtonState",mFavBtn.isChecked());
outState.getParcelableArrayList("newsList");
}
}
and
public class CommentActivity extends AppCompatActivity {
private static final String REQUIRED = "Required";
private static final String TAG = CommentActivity.class.getSimpleName();
Toolbar toolbar;
DatabaseReference mDatabase;
EditText titleEt;
EditText bodyEt;
Button commentBtn;
String newsTitle;
Intent i;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comment);
toolbar = (Toolbar) findViewById(R.id.comment_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("Add comment");
mDatabase = FirebaseDatabase.getInstance().getReference();
titleEt = (EditText) findViewById(R.id.comment_title);
bodyEt = (EditText) findViewById(R.id.comment_body);
commentBtn = (Button) findViewById(R.id.comment_btn);
i = getIntent();
newsTitle = i.getStringExtra("newsTitle");
commentBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
submitPost();
}
});
}
private void submitPost() {
final String title = titleEt.getText().toString();
final String body = bodyEt.getText().toString();
// Title is required
if (TextUtils.isEmpty(title)) {
titleEt.setError(REQUIRED);
return;
}
// Body is required
if (TextUtils.isEmpty(body)) {
bodyEt.setError(REQUIRED);
return;
}
// Disable button so there are no multi-posts
setEditingEnabled(false);
Toast.makeText(this, "Posting...", Toast.LENGTH_SHORT).show();
// [START single_value_read]
final String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabase.child("Users").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
User user = dataSnapshot.getValue(User.class);
// [START_EXCLUDE]
if (user == null) {
// User is null, error out
Log.e(TAG, "User " + userId + " is unexpectedly null");
Toast.makeText(CommentActivity.this,
"Error: could not fetch user.",
Toast.LENGTH_SHORT).show();
} else {
// Write new post
name = dataSnapshot.child("name").getValue().toString();
Calendar c = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
String strDate = sdf.format(c.getTime());
writeNewPost(userId,strDate,name,newsTitle, title, body);
}
// Finish this Activity, back to the stream
setEditingEnabled(true);
finish();
// [END_EXCLUDE]
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "getUser:onCancelled", databaseError.toException());
// [START_EXCLUDE]
setEditingEnabled(true);
// [END_EXCLUDE]
}
});
// [END single_value_read]
}
private void writeNewPost(String userId,String date,String
commentAuthor, String newsTitle, String commentTitle, String
commentBody){
String key = mDatabase.child("comments").push().getKey();
Comment comment = new Comment(userId, date,
commentAuthor,newsTitle,commentTitle,commentBody);
Map<String, Object> commentValues = comment.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/comments/" + key, commentValues);
mDatabase.updateChildren(childUpdates);
}
private void setEditingEnabled(boolean enabled) {
titleEt.setEnabled(enabled);
bodyEt.setEnabled(enabled);
if (enabled) {
commentBtn.setVisibility(View.VISIBLE);
} else {
commentBtn.setVisibility(View.GONE);
}
}
}
UPDATE
I used this
#Override
protected void onRestart() {
super.onRestart();
finish();
startActivity(getIntent());
}
and voila!
Some stuff I thought you would know when doing Android:
Basically, in android, you need to understand how the life cycle works. So, when you call queryFirebaseDb() from onCreate and from onResume, your app is doing two queries at the same time when activity starts initially.
Lifecycle is like this OnCreate -> onResume. So, it makes sense that when activity starts, query gets executed once on onCreate than on onResume based on your logic.
Answer is here
I noticed that you are using ArrayList<Comment> commentArrayList;, which is an ArrayList structure, which lets you have duplicate data. And, if you look into the behavior of Firebase and how your query is structured, it is like this,
Query query = mDatabase.child("comments").orderByChild("newsTitle").equalTo(newsTitle);
This query means that you are taking all the comments, the previous comment and the new comment, (not just new comment), which I think you either just want (1) to get recently added comment or (2) to replace the old comments with new one.
The first way of doing this sounds complicated to me, though that is not impossible. But, second way of doing is rather easy.
Therefore, to solve this,
simply, replace the arrayList you have with this data.
if(dataSnapshot.exists()){
ArrayList<Comment> tempComments = new ArrayList();
for(DataSnapshot dataSnapshots : dataSnapshot.getChildren()){
Comment comment = dataSnapshots.getValue(Comment.class);
//mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(userId);
tempComments.add(comment);
//Log.d(LOG_TAG, String.valueOf(commentArrayList.size()));
}
commentArrayList = tempComments; //assuming you want to store the data in the class fields
displayCommentsAdapter = new DisplayCommentsAdapter(this,commentArrayList);
mRecyclerView.setAdapter(displayCommentsAdapter);
displayCommentsAdapter.setCommentsData(commentArrayList);
noCommentsTextView.setVisibility(View.GONE);
//commentsTextView.setVisibility(View.VISIBLE);
}
I'm having difficulties with making my app persistent. When I rotate my phone the data on the screen doesnt change. But after I click on a button to retrieve a new fragment I get an error saying "Can not perform this action after onSaveInstanceState". I have googled and seen similiar problems but I still dont know how to approach and solve this.
I have an activity class, a controller class and two fragment classes.
The activity class has a navigationviewer with 2 buttons that triggers a fragmenttransaction. That is, on each button click it will replace the current fragment with the one set in the button listener. My controller class initalizes the system and the fragments are just the UI.
My activity class:
public class LoggedInActivity extends AppCompatActivity {
private final String TAG = "LoggedInActivity: ";
private Controller controller;
private TextView navName;
private NavigationView navigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.v(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logged_in);
if(savedInstanceState == null) {
Log.v(TAG, "savedInstanceState == null");
initComponents();
setNavName();
initListener();
initializeSystem();
} else {
Log.v(TAG, "savedInstanceState != null");
initComponents();
setNavName();
initListener();
this.controller = (Controller)savedInstanceState.getSerializable("controller");
}
}
private void initComponents() {
navigationView = (NavigationView) findViewById(R.id.navigation_view);
View headerView = navigationView.getHeaderView(0);
navName = (TextView) headerView.findViewById(R.id.tv_name_surname);
}
private void initListener() {
navigationView.setNavigationItemSelectedListener(new MyNavigationItemListener());
}
private void initializeSystem() {
Log.v(TAG, "new controller");
controller = new Controller(this, null);
}
public void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container_logged_in, fragment).commit();
}
private class MyNavigationItemListener implements NavigationView.OnNavigationItemSelectedListener {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch(item.getItemId()) {
case R.id.drawer_summary:
controller.setFragmentSummary();
break;
case R.id.drawer_income:
controller.setFragmentIncome();
break;
}
return false;
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable("controller", controller);
super.onSaveInstanceState(outState);
Log.v(TAG, "onSaveInstanceState, saving the controller");
}
}
My controller class:
public class Controller implements Serializable {
private final String TAG = "Controller: ";
/********************** Fragments ***********************/
private Fragment_Income fragment_income;
private Fragment_Summary fragment_summary;
/********************************************************/
/********************** Activities **********************/
private LoggedInActivity logged_in_activity;
/********************************************************/
public Controller(LoggedInActivity logged_in_activity) {
this.logged_in_activity = logged_in_activity;
initLoggedInFragments();
setFragmentSummary();
}
}
/* Initializes fragments that are connected to LoggedInActivity */
private void initLoggedInFragments() {
fragment_income = new Fragment_Income();
fragment_income.setController(this);
fragment_summary = new Fragment_Summary();
fragment_summary.setController(this);
}
/* use to replace current fragment with the given one */
private void replaceFragmentWith(Fragment fragment) {
logged_in_activity.setFragment(fragment);
}
/***********************************************************
* METHODS REGARDING FRAGMENT INCOME *
**********************************************************/
public void setFragmentIncome() {
replaceFragmentWith(fragment_income);
}
/* Summary fragment is started at first */
public void setFragmentSummary() {
replaceFragmentWith(fragment_summary);
}
}
Fragment_Income:
public class Fragment_Income extends Fragment implements Serializable{
private final String TAG = "Fragment_Income: ";
private Controller controller;
private FloatingActionButton fab_income;
private ListView lv_income;
private ArrayList<LvData> incomeData;
private LvAdapterIncome lvAdapterIncome;
public Fragment_Income() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.v(TAG, "onCreateView");
View view = inflater.inflate(R.layout.fragment_income, container, false); // Inflate the layout for this fragment
if(savedInstanceState != null) {
this.controller = (Controller) savedInstanceState.getSerializable("controller");
}
initComponents(view);
initListener();
setupListView();
return view;
}
private void initComponents(View view) {
fab_income = (FloatingActionButton) view.findViewById(R.id.fab_income);
lv_income = (ListView) view.findViewById(R.id.lv_income);
}
private void initListener() {
ButtonListener buttonListener = new ButtonListener();
fab_income.setOnClickListener(buttonListener);
}
private void setupListView() {
if (incomeData == null) { // checks if incomeData have been initalized before, if so do not change array to defualt
incomeData = new ArrayList<>();
lvAdapterIncome = new LvAdapterIncome(getContext(), incomeData);
}
lv_income.setAdapter(lvAdapterIncome);
}
public void setController(Controller controller) {
this.controller = controller;
}
#Override
public void onSaveInstanceState(Bundle outState) {
Log.v(TAG, "onSaveInstanceState, saving the controller");
outState.putSerializable("controller", this.controller);
super.onSaveInstanceState(outState);
}
}
Fragment_Summary:
public class Fragment_Summary extends Fragment implements Serializable {
private static final String TAG = "Fragment_Summary: ";
private Controller controller;
private TextView tv_user;
private TextView tv_total_revenue;
private TextView tv_total_expenditure;
private TextView tv_balance;
private float totalRevenue;
private float totalExpenditure;
private float balance;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_summary, container, false);// Inflate the layout for this fragment
initComponents(view);
setUserName();
if(savedInstanceState == null) {
//DO SOMETHING
}
return view;
}
private void addData() {
totalRevenue = controller.getTotalRevenue();
totalExpenditure = controller.getTotalExpenditure();
balance = totalRevenue - totalExpenditure;
tv_total_revenue.setText(String.valueOf(totalRevenue));
tv_total_expenditure.setText(String.valueOf(totalExpenditure));
tv_balance.setText(String.valueOf(balance));
}
private void initComponents(View view) {
tv_user = (TextView)view.findViewById(R.id.tv_user);
tv_total_revenue = (TextView)view.findViewById(R.id.tv_revenue);
tv_total_expenditure = (TextView)view.findViewById(R.id.tv_sum_exp);
tv_balance = (TextView)view.findViewById(R.id.tv_balance);
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("revenue", String.valueOf(balance));
outState.putString("totalExpenditure", String.valueOf(balance));
outState.putString("balance", String.valueOf(balance));
super.onSaveInstanceState(outState);
}
public void setController(Controller controller) {
this.controller = controller;
}
}
I have removed all the header files and some methods from my classes becuase I tought they were not relevant for this problem.
Here is the error log:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1434)
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1452)
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:708)
at android.app.BackStackRecord.commit(BackStackRecord.java:672)
at com.example.user.my_app.LoggedInActivity.setFragment(LoggedInActivity.java:85)
at com.example.user.my_app.Controller.replaceFragmentWith(Controller.java:89)
at com.example.user.my_app.Controller.setFragmentIncome(Controller.java:99)
at com.example.user.my_app.LoggedInActivity$MyNavigationItemListener.onNavigationItemSelected(LoggedInActivity.java:127)
at android.support.design.widget.NavigationView$1.onMenuItemSelected(NavigationView.java:156)
at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:822)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:156)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:969)
at android.support.design.internal.NavigationMenuPresenter$1.onClick(NavigationMenuPresenter.java:342)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
This looks like an activity state loss. See this excellent article by Alex Lockwood entitled "Fragment Transactions & Activity State Loss". I refer to it time and again.
To quote the intro to the posting:
The following stack trace and exception message has plagued StackOverflow ever since Honeycomb’s initial release:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
This post will explain why and when this exception is thrown, and will conclude with several suggestions that will help ensure it never crashes your application again.
I am using XWalkView to show a mobile web site as an application. My problem is when application goes background and comes back it reloads the page it shows. I want to keep it state and continue from that state when it comes from background. Here is my code:
public class MainActivity extends AppCompatActivity {
static final String URL = "https://www.biletdukkani.com.tr";
static final int MY_PERMISSIONS_REQUEST_ACCESS_LOCATION = 55;
static final String SHOULD_ASK_FOR_LOCATION_PERMISSION = "shouldAskForLocationPermission";
static final String TAG = "MainActivity";
static final String COMMAND = "/system/bin/ping -c 1 185.22.184.184";
static XWalkView xWalkWebView;
TextView noInternet;
static Bundle stateBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
stateBundle = savedInstanceState.getBundle("xwalk");
}
setContentView(R.layout.activity_main);
initNoInternetTextView();
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
stateBundle = savedInstanceState.getBundle("xwalk");
Log.d(TAG, "onRestoreInstanceState");
}
/**
* İnternet yok mesajı gösteren TextVidew'i ayarlar.
*/
private void initNoInternetTextView() {
Log.d(TAG, "initNoInternetTextView");
noInternet = (TextView) findViewById(R.id.no_internet);
if (noInternet != null) {
noInternet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
checkInternetConnection();
}
});
}
}
/**
* WebView'i ayarlar.
*/
private void initWebView() {
Log.d(TAG, "initWebView");
if (xWalkWebView == null) {
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
xWalkWebView = (XWalkView) findViewById(R.id.webView);
//xWalkWebView.clearCache(true);
xWalkWebView.load(URL, null);
xWalkWebView.setResourceClient(new BDResourceClient(xWalkWebView, progressBar));
}
}
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume");
checkLocationPermissions();
checkInternetConnection();
if (xWalkWebView != null && stateBundle != null) {
xWalkWebView.restoreState(stateBundle);
}
}
#Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
if (xWalkWebView != null) {
stateBundle = new Bundle();
xWalkWebView.saveState(stateBundle);
}
}
public void onSaveInstanceState(Bundle savedInstanceState) {
Log.d(TAG, "onSaveInstanceState");
// Save the user's current game state
savedInstanceState.putBundle("xwalk", stateBundle);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onBackPressed() {
Log.d(TAG, "onBackPressed");
if (xWalkWebView != null && xWalkWebView.getNavigationHistory().canGoBack()) {
xWalkWebView.getNavigationHistory().navigate(XWalkNavigationHistory.Direction.BACKWARD, 1);
} else {
super.onBackPressed();
}
}
}
I have also tried to add following lines to manifest but didn't work.
android:launchMode="singleTask"
android:alwaysRetainTaskState="true"
How can i do that?
Thanks in advcance.
One way would be to initialize the view inside a fragment which is set to retain it's instance.