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();
}
}
Related
I am having a Viewpager where i am loading data of different categories. I want to show a custom dialog popup whenever user stays on a particular category for 5 seconds or more asking the user if he/she wants to share the content. For that i have used a custom dialog and am hiding/showing based on the condition.
But the problem is, that if i want to open the dialog if the user stays on Viewpager item at position let's say 3, the dialog is opening for the Viewpager item at position 4.
I am not sure why it's referencing the wrong Viewpager item.
I am including the code of Adapter class for the reference.
ArticleAdapter.java
public class ArticleAdapter extends PagerAdapter {
public List<Articles> articlesListChild;
private LayoutInflater inflater;
Context context;
View rootView;
View customArticleShareDialog, customImageShareDialog;
public int counter = 0;
int contentType = 0;
int userId;
public ArticleAdapter(Context context, List<Articles> articlesListChild, int userId) {
super();
this.context = context;
this.userId = userId;
this.articlesListChild = articlesListChild;
}
#Override
public int getCount() {
return articlesListChild.size();
}
#Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((View) view);
}
private Timer timer;
private TimerTask timerTask;
public void startTimer() {
timer = new Timer();
initializeTimerTask();
timer.schedule(timerTask, 5*1000, 5*1000);
}
private void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
switch (contentType) {
case 1:
showShareDialog("articles");
break;
case 2:
showShareDialog("images");
break;
default :
// Do Nothing
}
}
};
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#SuppressLint("ClickableViewAccessibility")
#Override
public Object instantiateItem(ViewGroup container, final int position) {
inflater = LayoutInflater.from(container.getContext());
View viewLayout = inflater.inflate(R.layout.article_single_item, null, false);
final ImageView contentIv, imageContentIv;
final TextView sharingTextTv;
final LinearLayout articleShareBtn, articlesLayout, imagesLayout, customArticleShareDialog, customImageShareDialog;
contentIv = viewLayout.findViewById(R.id.content_iv);
articleShareBtn = viewLayout.findViewById(R.id.article_share_btn);
articlesLayout = viewLayout.findViewById(R.id.articles_layout);
imagesLayout = viewLayout.findViewById(R.id.images_layout);
imageContentIv = viewLayout.findViewById(R.id.image_content_iv);
sharingTextTv = viewLayout.findViewById(R.id.sharing_text_tv);
customArticleShareDialog = viewLayout.findViewById(R.id.articles_share_popup);
customImageShareDialog = viewLayout.findViewById(R.id.images_share_popup);
rootView = viewLayout.findViewById(R.id.post_main_cv);
viewLayout.setTag(rootView);
articleShareBtn.setTag(rootView);
// Images
if (articlesListChild.get(position).getArticleCatId() == 1) {
articlesLayout.setVisibility(GONE);
imagesLayout.setVisibility(View.VISIBLE);
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.placeholder);
Glide.with(context)
.setDefaultRequestOptions(requestOptions)
.load(articlesListChild.get(position).getArticleImage())
.into(imageContentIv);
imageContentIv.setScaleType(ImageView.ScaleType.FIT_XY);
sharingTextTv.setText("Found this image interesting? Share it with your friends.");
counter = 0;
startTimer();
// Articles
} else if (articlesListChild.get(position).getArticleCatId() == 2){
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.placeholder);
articlesLayout.setVisibility(View.VISIBLE);
Glide.with(context)
.setDefaultRequestOptions(requestOptions)
.load(articlesListChild.get(position).getArticleImage())
.into(contentIv);
contentIv.setScaleType(ImageView.ScaleType.FIT_XY);
sharingTextTv.setText("Found this article interesting? Share it with your friends.");
counter = 0;
startTimer();
}
container.addView(viewLayout, 0);
return viewLayout;
}
public void showShareDialog(String categoryType) {
if (categoryType.equalsIgnoreCase("articles")) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
customArticleShareDialog.setVisibility(View.VISIBLE);
}
});
} else if (categoryType.equalsIgnoreCase("images")) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
customImageShareDialog.setVisibility(View.VISIBLE);
}
});
}
}
}
ArticleActivity.java
public class ArticleActivity extends AppCompatActivity {
#BindView(R.id.toolbar)
Toolbar toolbar;
#BindView(R.id.drawer_layout)
DrawerLayout drawer;
#BindView(R.id.articles_view_pager)
ViewPager articlesViewPager;
#BindView(R.id.constraint_head_layout)
CoordinatorLayout constraintHeadLayout;
private ArticleAdapter articleAdapter;
private List<List<Articles>> articlesList = null;
private List<Articles> articlesListChild = new ArrayList<>();
private List<Articles> articlesListChildNew = new ArrayList<>();
SessionManager session;
Utils utils;
final static int MY_PERMISSIONS_WRITE_EXTERNAL_STORAGE = 1;
int userIdLoggedIn;
LsArticlesSharedPreference lsArticlesSharedPreference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ButterKnife.bind(this);
toolbar.setTitle("");
toolbar.bringToFront();
session = new SessionManager(getApplicationContext());
if (session.isLoggedIn()) {
HashMap<String, String> user = session.getUserDetails();
String userId = user.get(SessionManager.KEY_ID);
userIdLoggedIn = Integer.valueOf(userId);
} else {
userIdLoggedIn = 1000;
}
utils = new Utils(getApplicationContext());
String storedTime = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("lastUsedDate", "");
System.out.println("lastUsedDate : " + storedTime);
if (utils.isNetworkAvailable()) {
insertData();
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
toggle.getDrawerArrowDrawable().setColor(getResources().getColor(R.color.colorWhite));
drawer.addDrawerListener(toggle);
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSIONS_WRITE_EXTERNAL_STORAGE);
}
articleAdapter = new ArticleAdapter(getApplicationContext(), articlesListChild, userIdLoggedIn);
toggle.syncState();
clickListeners();
toolbar.setVisibility(View.GONE);
} else {
Intent noInternetIntent = new Intent(getApplicationContext(), NoInternetActivity.class);
startActivity(noInternetIntent);
}
}
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
finishAffinity();
super.onBackPressed();
}
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onStop() {
super.onStop();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
#Override
public boolean onSupportNavigateUp() {
finish();
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
articleAdapter.notifyDataSetChanged();
insertData();
Toast.makeText(this, "Refreshed", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#SuppressLint("ClickableViewAccessibility")
public void clickListeners() {
}
private void insertData() {
Intent intent = new Intent(getBaseContext(), OverlayService.class);
startService(intent);
final SweetAlertDialog pDialog = new SweetAlertDialog(ArticleActivity.this, SweetAlertDialog.PROGRESS_TYPE);
pDialog.getProgressHelper().setBarColor(getResources().getColor(R.color.colorPrimary));
pDialog.setTitleText("Loading");
pDialog.setCancelable(false);
pDialog.show();
Api.getClient().getHomeScreenContents(userIdLoggedIn, new Callback<ArticlesResponse>() {
#Override
public void success(ArticlesResponse articlesResponse, Response response) {
articlesList = articlesResponse.getHomeScreenData();
if (!articlesList.isEmpty()) {
for (int i = 0; i < articlesList.size(); i++) {
articlesListChildNew = articlesList.get(i);
articlesListChild.addAll(articlesListChildNew);
}
articleAdapter = new ArticleAdapter(getApplicationContext(), articlesList, articlesListChild, userIdLoggedIn, toolbar);
articlesViewPager.setAdapter(articleAdapter);
articleAdapter.notifyDataSetChanged();
pDialog.dismiss();
} else {
List<Articles> savedArticles = lsArticlesSharedPreference.getFavorites(getApplicationContext());
if (!savedArticles.isEmpty()) {
articleAdapter = new ArticleAdapter(getApplicationContext(), articlesList, savedArticles, userIdLoggedIn, toolbar);
articlesViewPager.setAdapter(articleAdapter);
articleAdapter.notifyDataSetChanged();
pDialog.dismiss();
} else {
Api.getClient().getAllArticles(new Callback<AllArticlesResponse>() {
#Override
public void success(AllArticlesResponse allArticlesResponse, Response response) {
articlesListChild = allArticlesResponse.getArticles();
articleAdapter = new ArticleAdapter(getApplicationContext(), articlesList, articlesListChild, userIdLoggedIn, toolbar);
articlesViewPager.setAdapter(articleAdapter);
articleAdapter.notifyDataSetChanged();
};
#Override
public void failure(RetrofitError error) {
Log.e("articlesData", error.toString());
}
});
pDialog.dismiss();
}
}
}
#Override
public void failure(RetrofitError error) {
pDialog.dismiss();
Toast.makeText(ArticleActivity.this, "There was some error fetching the data.", Toast.LENGTH_SHORT).show();
}
});
}
}
Issue reason:
You face this issue because the viewpager preload fragments in background. It means that when you see 3rd fragment, the viewpager is instantiating 4th. Due to this workflow your timer for 3rd screen is cancelled and timer for 4th screen is started. Check out this link to understand what is going on.
Solution:
I would do next:
Then set page change listener for your adapter. How to do it
In this listener you can get current page and start timer for this page (and cancel timer for previously visible page).
You don't need to call startTimer() method when you instantiate item in instantiateItem() method.
I have a problem with my RecyclerView.
I have a ProductDetailActivity which shows the detail of a product and i have a RecyclerView with its adapter in it.
The user can click on the give rating button which navigates to the RatingActivity where you can give a rating to the product.
The problem is that when i submit my rating and automatically go back to my RatingActivity, the RecyclerView does not get the recently added rating. i have to go back to my productlist and reclick on the product to see the recently added rating.
Here is my code:
ProductDetailActivity:
public class ProductDetailActivity extends AppCompatActivity {
public AppDatabase appDatabase;
private static final String DATABASE_NAME = "Database_Shop";
private RecyclerView mRecycleviewRating;
private RatingAdapter mAdapterRating;
private Button btnGoToRatingActivity;
List<Rating> ratings;
Product p;
int id;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_detail);
appDatabase = Room.databaseBuilder(getApplicationContext(),AppDatabase.class,DATABASE_NAME)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();
btnGoToRatingActivity = findViewById(R.id.btn_goToRatingActivity);
Intent intent = getIntent();
id = intent.getIntExtra("productid", -1);
// pour montrer tous les ratings d'un produit, tu fais un getall
p = appDatabase.productDAO().getProductById(id);
ImageView imageView = findViewById(R.id.imageDetail);
TextView textViewName = findViewById(R.id.txt_nameDetail);
TextView textViewAuthor = findViewById(R.id.txt_authorDetail);
TextView textViewCategory = findViewById(R.id.txt_categoryDetail);
TextView textViewDetail = findViewById(R.id.txt_descriptionDetail);
Picasso.get().load(p.getProductImage()).fit().centerInside().into(imageView);
textViewName.setText(p.getProductName());
textViewAuthor.setText(p.getProductAuthor());
textViewCategory.setText(p.getProductCategory());
textViewDetail.setText(p.getProductDescription());
ratings = appDatabase.ratingDAO().getRatingByProductId(id);
mRecycleviewRating = findViewById(R.id.recyclerRating_view);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecycleviewRating.setLayoutManager(linearLayoutManager);
//recyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapterRating = new RatingAdapter(ratings);
mRecycleviewRating.setAdapter(mAdapterRating);
btnGoToRatingActivity.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(ProductDetailActivity.this, RatingActivity.class);
i.putExtra("productid", p.getProduct_id());
startActivity(i);
}
});
mAdapterRating.notifyDataSetChanged();
}
#Override
public void onResume() {
super.onResume();
ratings = appDatabase.ratingDAO().getRatingByProductId(id); // reload the items from database
mAdapterRating.notifyDataSetChanged();
System.out.println(mAdapterRating.ratings.size());
}
}
RatingActivity:
public class RatingActivity extends AppCompatActivity implements RatingGiveFragment.RatingListener {
RelativeLayout mRelativeLayout;
private Button btnConfirmRating;
private EditText mComment;
private RatingBar mRatingBar;
public AppDatabase appDatabase;
private RatingAdapter mAdapter;
List<Rating> ratings;
private static final String DATABASE_NAME = "Database_Shop";
Product p;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rating);
appDatabase = Room.databaseBuilder(getApplicationContext(),AppDatabase.class,DATABASE_NAME)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();
int idProduct = RatingActivity.this.getIntent().getIntExtra("productid",-1);
p = appDatabase.productDAO().getProductById(idProduct);
mRatingBar = findViewById(R.id.rating_bar);
mComment = findViewById(R.id.txt_insertOpinionText);
mRelativeLayout = findViewById(R.id.activity_rating);
btnConfirmRating = findViewById(R.id.buttonConfirmRating);
mAdapter = new RatingAdapter(ratings);
btnConfirmRating.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!checkEmptyFields()) {
Rating rating = new Rating(p.getProduct_id(),UserConnected.connectedUser.getUser_id(),mRatingBar.getRating(), UserConnected.connectedUser.getUsername(), mComment.getText().toString());
appDatabase.ratingDAO().insertRating(rating);
mAdapter.notifyDataSetChanged();
finish();
}else{
Toast.makeText(RatingActivity.this, "Empty Fields", Toast.LENGTH_SHORT).show();
}
}
});
}
/*private class insertRating extends AsyncTask<String,Integer, Integer>
{
#Override
protected Integer doInBackground(String... strings) {
Rating rating = new Rating(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), Integer.parseInt(strings[2]), strings[3], strings[4]);
appDatabase.ratingDAO().insertRating(rating);
return 1;
}
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
if (integer == 1)
{
Toast.makeText(getApplicationContext(), getString(R.string.createRating), Toast.LENGTH_SHORT).show();
}
}
}*/
#Override
public void ratingChanged(int newRating) {
RatingTextFragment textFragment = (RatingTextFragment) getSupportFragmentManager().findFragmentById(R.id.fmt_text);
textFragment.setRating(newRating);
}
private boolean checkEmptyFields(){
if(TextUtils.isEmpty(mComment.getText().toString())){
return true;
}else{
return false;
}
}
}
RatingAdapter:
public class RatingAdapter extends RecyclerView.Adapter<RatingAdapter.RatingViewHolder> {
List<Rating> ratings;
public RatingAdapter(List<Rating> ratings){
this.ratings = ratings;
}
#NonNull
#Override
public RatingViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.rating_row,viewGroup, false);
return new RatingViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RatingViewHolder ratingViewHolder, int position) {
ratingViewHolder.ratingUsername.setText(ratings.get(position).getRatingUsername());
ratingViewHolder.ratingNumber.setText(String.valueOf(ratings.get(position).getRatingNumber()) + "/5");
ratingViewHolder.ratingComment.setText(ratings.get(position).getRatingText());
}
#Override
public int getItemCount() {
return ratings.size();
}
public static class RatingViewHolder extends RecyclerView.ViewHolder{
public TextView ratingUsername;
public TextView ratingNumber;
public TextView ratingComment;
public RatingViewHolder(#NonNull View itemView) {
super(itemView);
ratingUsername = itemView.findViewById(R.id.txt_usernamerating);
ratingNumber = itemView.findViewById(R.id.num_rating);
ratingComment = itemView.findViewById(R.id.txt_ratingComment);
}
}
}
Pictures:
You get no update in the ProductDetailActivity because you are not updating the data object ratings in the ProductDetailActivity that is the basis for the RatingAdapter.
It would be better to use startActivityForResult in the onClick()method of the ProductDetailActivity. Then you need to override the onActivityResult() method in the ProductDetailActivity. Evaluate the return values and update your data source if necessary, then call notifyDataSetChanged.
This is just pseudo code!
Changes to ProductDetailActivity:
btnGoToRatingActivity.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(ProductDetailActivity.this, RatingActivity.class);
i.putExtra("productid", p.getProduct_id());
// with this you are telling the activity to expect results and..
//..to deal with them in onActivityResult
startActivityForResult(i, 1);
}
});
// You do not need this next line because setting the adaper triggers the first
//mAdapterRating.notifyDataSetChanged();
}
Add the onActivityResult() method to the ProductDetailActivity.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == Activity.RESULT_OK){
// trigger a method to update the data object that is linked to the adapter
ratings = appDatabase.ratingDAO().getRatingByProductId(id);
// and now that the data has actually been updated you can call notifyDataSetChanged!!
mAdapterRating.notifyDataSetChanged();
}
if (resultCode == Activity.RESULT_CANCELED) {
//Probably do nothing or make a Toast "Canceled"??
}
}
}
Changes to RatingActivity:
btnConfirmRating.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!checkEmptyFields()) {
// I will just assume this works!
Rating rating = new Rating(p.getProduct_id(),UserConnected.connectedUser.getUser_id(),mRatingBar.getRating(), UserConnected.connectedUser.getUsername(), mComment.getText().toString());
appDatabase.ratingDAO().insertRating(rating);
Intent intent = new Intent();
//If you need to return some value.. do it here other you do not need it
//intent.putExtra("result", result);
setResult(Activity.RESULT_OK, intent);
finish();
}else{
Toast.makeText(RatingActivity.this, "Empty Fields", Toast.LENGTH_SHORT).show();
}
}
});
Please be aware in RatingActivity that in btnConfirmRating.setOnClickListener notifying the adapter with mAdapter.notifyDataSetChanged(); does nothing: firstly, because the adapter in the RatingActivity has nothing to do with the adapter in the ProductDetailActivity; secondly: you call finish(); in the next line of code.
I am creating an android app, where I'll be asking for multiple types of questions using RadioButtons. I don't want to make multiple Activities for these questions. Can anyone please tell me how to do that with a short example, of at least two questions?
You can use multiples fragments... or call the activity itself multiple times...
I did an app like yours and i choose the first method!
This is some fragment of a project that i wrote, and the activity that manipulate it, you will have to change it according to your needs.
Activity
public class CollectActivity extends FragmentActivity {
MyPageAdapter pageAdapter;
NonSwipeableViewPager pager;
SpringIndicator springIndicator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collect);
List<Fragment> fragments = getFragments();
pager = (NonSwipeableViewPager) findViewById(R.id.view_pager);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
PagerModelManager manager = new PagerModelManager();
manager.addCommonFragment(fragments, getTitles());
ModelPagerAdapter adapter = new ModelPagerAdapter(getSupportFragmentManager(), manager);
pager.setAdapter(adapter);
springIndicator = (SpringIndicator) findViewById(R.id.indicator);
springIndicator.setViewPager(pager);
springIndicator.setOnTabClickListener(new TabClickListener() {
#Override
public boolean onTabClick(int position) {
return false;
}
});
}
private List<Fragment> getFragments() {
List<Fragment> fList = new ArrayList<Fragment>();
fList.add(CollectFragment.newInstance("Fragment 1"));
fList.add(CollectFragment.newInstance("Fragment 2"));
fList.add(CollectFragment.newInstance("Fragment 3"));
//add your fragments with a loop
return fList;
}
private List<String> getTitles() {
return Lists.newArrayList("1", "2", "3");
}
public void swipeFragment() {
pager.setCurrentItem(pager.getCurrentItem() + 1);
}
public int getFragment() {
return pager.getCurrentItem();
}
}
Fragment
public class CollectFragment extends Fragment {
private Button openButton;
private Button confirmationCloseButton;
private Button yesRenew;
private Button noRenew;
private BroadcastReceiver udpMessages;
public static final String EXTRA_MESSAGE = "EXTRA_MESSAGE";
public static final CollectFragment newInstance(String message) {
CollectFragment f = new CollectFragment();
Bundle bdl = new Bundle(1);
bdl.putString(EXTRA_MESSAGE, message);
f.setArguments(bdl);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String message = getArguments().getString(EXTRA_MESSAGE);
View v = null;
if (message.compareTo("Fragment 1") == 0) {
v = inflater.inflate(R.layout.fragment_collect_open, container, false);
openButton = (Button) v.findViewById(R.id.open_button);
openButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i2 = new Intent();
i2.setComponent(new ComponentName("qira.com.locker", "qira.com.locker.Service.MessageService"));
i2.putExtra("Message", "CONFIRM_LOCKER_1_CLOSED");
getContext().startService(i2);
}
});
}
if (message.compareTo("Fragment 2") == 0) {
v = inflater.inflate(R.layout.fragment_collect_close, container, false);
confirmationCloseButton = (Button) v.findViewById(R.id.confirmation_close_button);
confirmationCloseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i2 = new Intent();
i2.setComponent(new ComponentName("qira.com.locker", "qira.com.locker.Service.MessageService"));
i2.putExtra("Message", "OPEN_LOCKER_1");
getContext().startService(i2);
}
});
}
if (message.compareTo("Fragment 3") == 0) {
v = inflater.inflate(R.layout.fragment_collect_renew, container, false);
yesRenew = (Button) v.findViewById(R.id.yes_button);
noRenew = (Button) v.findViewById(R.id.no_button);
yesRenew.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
((CollectActivity) getActivity()).swipeFragment();
}
});
noRenew.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(getContext(), ReserveActivity.class);
startActivity(i);
}
});
}
return v;
}
#Override
public void onResume() {
super.onResume();
udpMessages = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals("UDP.MESSAGES.COLLECT")) {
if (intent.getExtras().getString("Type").compareTo("OPEN_LOCKER_1-LOCKER_OPENED") == 0) {
if (((CollectActivity) getActivity()).getFragment() != 0) { // onCreateView called twice, dont know why... workaround to solve this problem
((CollectActivity) getActivity()).swipeFragment();
}
}
if (intent.getExtras().getString("Type").compareTo("CONFIRM_LOCKER_1_CLOSED-TRUE") == 0) {
if (((CollectActivity) getActivity()).getFragment() != 1) { // onCreateView called twice, dont know why... workaround to solve this problem
((CollectActivity) getActivity()).swipeFragment();
}
}
}
}
};
getContext().registerReceiver(udpMessages, new IntentFilter("UDP.MESSAGES.COLLECT"));
}
#Override
public void onPause() {
super.onPause();
getContext().unregisterReceiver(udpMessages);
}
#Override
public void onDestroyView() {
super.onDestroyView();
}
}
I am trying to implement callback between AsyncTask and Fragment but cannot find correct info how to do it. The issue is that all callback implementations are between activity and asynctask but I need between fragment and asynctask. Could someone give me small working example how to implement it without activity.
My action structure: Fragment call DialogFragment -> choose something and send server request to async task -> async task process everything and update view and some variables. My main problem is that I call prepareData() only once in onCreate and when I walk between other fragment and returns come back I see old data. That is to say there is not enough to update only view in onPost of asynctask. It will be good to have callback which will update the whole variables.
public class TermsAndConditionsFragment extends SherlockFragment implements OnClickListener, OnTouchListener, OnItemClickListener, onTaskListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fm = getSherlockActivity().getSupportFragmentManager();
prepareData();
}
public void prepareData() {
termsAndConditionsM = new TermsAndConditionsManager(getSherlockActivity());
termsAndConditions = termsAndConditionsM.getTermsAndConditions();
if (termsAndConditions != null) {
int totalPayments = Integer.valueOf(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
if (totalPayments > 0) {
paymentsData = termsAndConditionsM.getpayments();
if (paymentsData != null) {
payments = new ArrayList<Payment>();
for (int i = 1; i <= totalPayments; i++) {
paymentValues = new Payment();
paymentValues.setPaymentID(Integer.valueOf(paymentsData.get(ServerAPI.PAYMENT_NO + "_" + i)));
paymentValues.setPaymentDate(paymentsData.get(ServerAPI.PAYMENT_DATE + "_" + i));
paymentValues.setPaymentTotalAmount(paymentsData.get(ServerAPI.PAYMENT_TOTAL + "_" + i));
payments.add(paymentValues);
}
}
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = init(inflater, container);
if (payments != null || termsAndConditions != null)
updateTermsAndConditionsView();
return rootView;
}
private View init(LayoutInflater inflater, ViewGroup container) {
rootView = inflater.inflate(R.layout.fragment_terms_and_conditions, container, false);
...
return rootView;
}
public void updateTermsAndConditionsView() {
etHowMuch.setText("£" + termsAndConditions.get(ServerAPI.AMOUNT_OF_CREDIT));
etForHowLong.setText(Helpers.ConvertDays2Date(Integer.valueOf(termsAndConditions.get(ServerAPI.TERM_OF_AGREEMENT_IN_DAYS))));
PaymentAdapter adapter = new PaymentAdapter(getSherlockActivity(), R.layout.custom_loan_item, payments);
lvPayments.setAdapter(adapter);
tvNoOfPayments.setText(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
tvFirstPayment.setText(termsAndConditions.get(ServerAPI.FIRST_PAYMENT_DATE));
tvTotalRepayable.setText("£" + termsAndConditions.get(ServerAPI.TOTAL_REPAYABLE));
}
#Override
public void onClick(View v) {
ft = fm.beginTransaction();
howMuch = etHowMuch.getText().toString();
forHowLong = etForHowLong.getText().toString();
switch (v.getId()) {
case R.id.etHowMuch:
f = new NumberPaymentsPickerFragment();
args = new Bundle();
args.putInt(Const.HOW_MUCH, Integer.valueOf(howMuch.replace("£", "")));
args.putDouble(ServerAPI.PAYMENT_STEP, Const.PAYMENT_STEP);
args.putString(Const.STATE, ServerAPI.TERMS_AND_CONDITIONS);
f.setArguments(args);
f.setTargetFragment(this, DIALOG_FRAGMENT);
f.show(getActivity().getSupportFragmentManager(), Const.HOW_MUCH);
break;
case R.id.etForHowLong:
f = new NumberPaymentsPickerFragment();
args = new Bundle();
args.putInt(Const.FOR_HOW_LONG, Integer.valueOf(Helpers.ConvertDate2Days(forHowLong)));
args.putDouble(ServerAPI.PAYMENT_STEP, Const.PAYMENT_STEP);
args.putString(Const.STATE, ServerAPI.TERMS_AND_CONDITIONS);
f.setArguments(args);
f.setTargetFragment(this, DIALOG_FRAGMENT);
f.show(getActivity().getSupportFragmentManager(), Const.FOR_HOW_LONG);
break;
case R.id.tvPersonalDetails:
sfm.saveCurFragment(ServerAPI.PERSONAL_DETAILS, 0);
ft.replace(android.R.id.content, new PersonalDetailsFragment(), ServerAPI.PERSONAL_DETAILS).addToBackStack(null).commit();
break;
case R.id.tvAgreementDetails:
sfm.saveCurFragment(ServerAPI.AGREEMENT_DETAILS, 0);
ft.replace(android.R.id.content, new AgreementDetailsFragment(), ServerAPI.AGREEMENT_DETAILS).addToBackStack(null).commit();
break;
case R.id.bApply:
break;
}
#Override
public void onUpdateData() {
Log.d(TAG, "Update data");
}
}
DialogFragment:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
...
}
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
return createDialog(v, R.string.for_how_long, etHowMuch, etForHowLong, etPromotionCode);
}
return null;
}
private Dialog createDialog(View view, int titleResID, final EditText howMuchField, final EditText forHowLongField, final EditText promotionCodeField) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(titleResID);
builder.setView(view);
builder.setPositiveButton(R.string.set, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
doShowProgress();
}
private void doShowProgress() {
ExecuteServerTaskBackground task = new
ExecuteServerTaskBackground(getActivity());
task.action = ServerAPI.GET_TERMS_AND_CONDITIONS;
onTaskListener listener = new onTaskListener() {
#Override
public void onUpdateData() {
Log.d(TAG, "Updaaate");
}
};
task.setListener(listener);
task.args = args;
task.execute();
}
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
return builder.create();
}
AsyncTask:
onTaskListener mListener;
public interface onTaskListener {
void onUpdateData();
}
public void setListener(onTaskListener listener){
mListener = listener;
}
public ExecuteServerTaskBackground(Activity activity) {
this.mActivity = activity;
this.mContext = activity.getApplicationContext();
}
#Override
protected void onPreExecute() {
pb = (ProgressBar) mActivity.findViewById(R.id.progressBar1);
pb.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
ServerAPI server = new ServerAPI(mContext);
if (!args.isEmpty())
server.serverRequest(action, args);
else
server.serverRequest(action, null);
return null;
}
#Override
protected void onPostExecute(Void result) {
mListener.onUpdateData();
//There is I just update view but how to update whole variables throughtout callback?
// tvNoOfPayments = (TextView) mActivity.findViewById(R.id.tvNoOfPaymentsValue);
// tvFirstPayment = (TextView) mActivity.findViewById(R.id.tvFirstPaymentValue);
// tvTotalRepayable = (TextView) mActivity.findViewById(R.id.tvTotalRepayableValue);
//
// lvPayments = (ListView) mActivity.findViewById(R.id.lvData);
//
// termsConditionsM = new TermsAndConditionsManager(mContext);
//
// termsAndConditions = termsConditionsM.getTermsAndConditions();
//
// int totalPayments = Integer.valueOf(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
//
// if (totalPayments > 0) {
// if (termsAndConditions != null) {
// tvNoOfPayments.setText(termsAndConditions.get(ServerAPI.NO_OF_PAYMENTS));
// tvFirstPayment.setText(termsAndConditions.get(ServerAPI.FIRST_PAYMENT_DATE));
// tvTotalRepayable.setText("£" + termsAndConditions.get(ServerAPI.TOTAL_REPAYABLE));
// }
//
// paymentsData = termsConditionsM.getpayments();
//
// if (paymentsData != null) {
// Log.d(TAG, paymentsData.toString());
//
// payments = new ArrayList<Payment>();
//
// for (int i = 1; i <= totalPayments; i++) {
// paymentValues = new Payment();
// paymentValues.setPaymentID(Integer.valueOf(paymentsData.get(ServerAPI.PAYMENT_NO + "_" + i)));
// paymentValues.setPaymentDate(paymentsData.get(ServerAPI.PAYMENT_DATE + "_" + i));
// paymentValues.setPaymentTotalAmount(paymentsData.get(ServerAPI.PAYMENT_TOTAL + "_" + i));
// payments.add(paymentValues);
// }
//
// PaymentAdapter adapter = new PaymentAdapter(mContext, R.layout.custom_loan_item, payments);
// lvPayments.setAdapter(adapter);
// }
//
}
pb.setVisibility(View.GONE);
super.onPostExecute(result);
}
Without taking your code in consideration I will post the most essential to make a functional callback.
TestFragment:
public class TestFragment extends Fragment {
/* Skipping most code and I will only show you the most essential. */
private void methodThatStartsTheAsyncTask() {
TestAsyncTask testAsyncTask = new TestAsyncTask(new FragmentCallback() {
#Override
public void onTaskDone() {
methodThatDoesSomethingWhenTaskIsDone();
}
});
testAsyncTask.execute();
}
private void methodThatDoesSomethingWhenTaskIsDone() {
/* Magic! */
}
public interface FragmentCallback {
public void onTaskDone();
}
}
TestAsyncTask:
public class TestAsyncTask extends AsyncTask<Void, Void, Void> {
private FragmentCallback mFragmentCallback;
public TestAsyncTask(FragmentCallback fragmentCallback) {
mFragmentCallback = fragmentCallback;
}
#Override
protected Void doInBackground(Void... params) {
/* Do your thing. */
return null;
}
#Override
protected void onPostExecute(Void result) {
mFragmentCallback.onTaskDone();
}
}
I've found several questions about this, none of which help me. Each question relates to other functions and views I don't implement in my fragments, and the issue is not that I need to swap my method getting the FragmentManager to getChildFragmentManager() anywhere in my fragments, because I don't need to get a FragmentManager there.
I'm guessing that my issue stems from the fragments and not the FragmentTabHost in the main activity, but I am not really sure. At all. All I know is that when you page between tabs, the adapter content disappears, but not the fragment itself. All views are still functional, so the functionality of each fragment remains intact.
This issue popped up only after I added a tab change listener for when to initialize the adapter for my chat fragment.
Note that the content of the tabs is fine when they are first initialized, but when you return to the tab the content in the adapters empty. This means that the tab that is not initialized yet when the FragmentTabHost is created, the hidden tabs haven't been initialized yet, so they will still work the first time you page over to them.
Through debugging, I can see that this issue occurs when the transition happens, and all adapters will remain empty for the duration of the usage session. I put this snippit of code before the initial checks in my tabHost.setOnTabChangedListener call:
//Before paging back to an initialized tab for the first time, the adapters of the initialized tab is populated.
Log.d("test", "pre");
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//At this point, the adapter is empty.
Log.d("test", "post");
}
}, 50);
The two fragments are as follows:
public class GroupTasksFragment extends Fragment {
public ArrayAdapter<String> adapter;
private Context context;
public ListView taskListView;
public GroupTasksFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_group_tasks, container, false);
taskListView = (ListView) rootView.findViewById(R.id.tasksList);
adapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, new ArrayList<String>());
taskListView.setAdapter(adapter);
return rootView;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
#Override
public void onDetach() {
super.onDetach();
}
}
public class GroupChatFragment extends Fragment{
public ArrayAdapter<String> adapter;
private Context context;
public ListView chatListView;
public GroupChatFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_group_chat, container, false);
chatListView = (ListView) rootView.findViewById(R.id.chatList);
adapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, new ArrayList<String>());
chatListView.setAdapter(adapter);
return rootView;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
#Override
public void onDetach() {
super.onDetach();
}
}
The main activity with the FragmentTabHost (I have excluded methods that just take input and send content to PubNub):
public class GroupContentActivity extends AppCompatActivity {
private GroupChatFragment chatFrag;
private GroupTasksFragment taskFrag;
private FragmentTabHost tabHost;
private PubNub connection;
private String groupName;
private String nickName;
private boolean chatFragInitialized = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_group_content);
tabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
tabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
tabHost.addTab(tabHost.newTabSpec("tasks").setIndicator("Tasks"),
GroupTasksFragment.class, null);
tabHost.addTab(tabHost.newTabSpec("chat")
.setIndicator("Chat"), GroupChatFragment.class, null);
groupName = getIntent().getStringExtra("groupName");
nickName = getIntent().getStringExtra("nickName");
PNConfiguration config = new PNConfiguration();
config.setPublishKey(Constants.publishKey);
config.setSubscribeKey(Constants.subscribeKey);
connection = new PubNub(config);
tabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
#Override
public void onTabChanged(String tabId) {
if (!chatFragInitialized && tabId.equals("chat")) {
chatFragInitialized = true;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
chatFrag = (GroupChatFragment) getSupportFragmentManager().findFragmentByTag("chat");
connection.history()
.channel(groupName)
.count(50)
.async(new PNCallback<PNHistoryResult>() {
#Override
public void onResponse(PNHistoryResult result, PNStatus status) {
for (PNHistoryItemResult item : result.getMessages()) {
final String[] sForm = item.getEntry().getAsString().split(">>>>");
String m = "";
if (sForm.length > 2) {
for (int x = 1; x < sForm.length; x++) {
m += sForm[x];
}
} else {
m = sForm[1];
}
final String mCopy = m;
runOnUiThread(new Runnable() {
#Override
public void run() {
switch (sForm[0]) {
case "groupCreated":
chatFrag.adapter.clear();
break;
case "chat":
chatFrag.adapter.add(mCopy);
}
}
});
}
}
});
}
}, 50);
}
}
});
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
taskFrag = (GroupTasksFragment) getSupportFragmentManager().findFragmentByTag("tasks");
connection.history()
.channel(groupName)
.count(50)
.async(new PNCallback<PNHistoryResult>() {
#Override
public void onResponse(PNHistoryResult result, PNStatus status) {
for (PNHistoryItemResult item : result.getMessages()) {
final String[] sForm = item.getEntry().getAsString().split(">>>>");
String m = "";
if (sForm.length > 2) {
for (int x = 1; x < sForm.length; x++) {
m += sForm[x];
}
} else {
m = sForm[1];
}
final String mCopy = m;
runOnUiThread(new Runnable() {
#Override
public void run() {
switch (sForm[0]) {
case "addTask":
if (taskFrag.adapter.getPosition(mCopy) < 0) {
taskFrag.adapter.add(mCopy);
}
break;
case "deleteTask":
if (taskFrag.adapter.getPosition(mCopy) >= 0) {
taskFrag.adapter.remove(mCopy);
}
break;
case "groupCreated":
taskFrag.adapter.clear();
break;
}
}
});
}
}
});
connection.addListener(new SubscribeCallback() {
#Override
public void status(PubNub pubnub, PNStatus status) {
if (status.getCategory() == PNStatusCategory.PNUnexpectedDisconnectCategory) {
Toast.makeText(getApplicationContext(), "You were disconnected!", Toast.LENGTH_SHORT).show();
} else if (status.getCategory() == PNStatusCategory.PNConnectedCategory) {
if (status.getCategory() == PNStatusCategory.PNConnectedCategory) {
pubnub.publish().channel(groupName).message("chat>>>><ADMIN> User '" + nickName + "' Connected").async(new PNCallback<PNPublishResult>() {
#Override
public void onResponse(PNPublishResult result, PNStatus status) {
}
});
}
} else if (status.getCategory() == PNStatusCategory.PNReconnectedCategory) {
Toast.makeText(getApplicationContext(), "You were reconnected!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void message(PubNub pubnub, PNMessageResult message) {
final String[] sForm = message.getMessage().getAsString().split(">>>>");
String m = "";
if (sForm.length > 2) {
for (int x = 1; x < sForm.length; x++) {
m += sForm[x];
}
} else {
m = sForm[1];
}
final String mCopy = m;
runOnUiThread(new Runnable() {
#Override
public void run() {
switch (sForm[0]) {
case "chat":
if (chatFragInitialized) {
chatFrag.adapter.add(mCopy);
runOnUiThread(new Runnable() {
#Override
public void run() {
chatFrag.chatListView.setSelection(chatFrag.adapter.getCount() - 1);
}
});
}
break;
case "addTask":
taskFrag.adapter.add(mCopy);
connection.publish().channel(groupName).message("chat>>>><ADMIN> Task '" + mCopy + "' added.").async(new PNCallback<PNPublishResult>() {
#Override
public void onResponse(PNPublishResult pnPublishResult, PNStatus pnStatus) {
}
});
break;
case "deleteTask":
taskFrag.adapter.remove(mCopy);
connection.publish().channel(groupName).message("chat>>>><ADMIN> Task '" + mCopy + "' deleted.").async(new PNCallback<PNPublishResult>() {
#Override
public void onResponse(PNPublishResult pnPublishResult, PNStatus pnStatus) {
}
});
break;
}
}
});
}
#Override
public void presence(PubNub pubnub, PNPresenceEventResult presence) {
}
});
connection.subscribe().channels(java.util.Collections.singletonList(groupName)).execute();
}
}, 100);
}
#Override
public void onDestroy(){
super.onDestroy();
connection.publish().channel(groupName).message("chat>>>><ADMIN> User '" + nickName + "' Logged Out.").async(new PNCallback<PNPublishResult>() {
#Override
public void onResponse(PNPublishResult pnPublishResult, PNStatus pnStatus) {
}
});
connection.disconnect();
Toast.makeText(getApplicationContext(), "Logged out", Toast.LENGTH_SHORT).show();
}
//More Methods
}
Also note that the issue is not that I need to store the FragmentManager instance, as that doesn't do anything.
I found my issue. It turns out that every time a fragment is paged to in the FragmentTabHost, it's createView method is called again, and only that method, so by setting the adapter in the fragment to empty in that view, which I thought was only at the start, I reset the adapter each time.
I fixed this by keeping the adapter content as an instance variable list object that I add or remove strings to/from when I want to change the adapter. DO NOT ALSO PUT THE STRINGS IN THE ADAPTER, updating the list is enough. The list will directly add it to the adapter.
Also note that if you set the initial content outside of the fragment, it may not show when the tabs are first initialized. Just be careful of your statement ordering and when things are called. Fragment construction is funky business.
Then, I set the adapter to whatever is in the list each time the createView method is called.