Bug: Slider Appearing Every time using viewpager - android

i am making a slider walkthrough which is introduced in the app for the first item when the user clicks the app....and it is gone when the user again open it.
like this: https://www.youtube.com/watch?v=va2IRW_e7_w
the problem is that i am regaining it again and again whenever i opent the app, its a small mistake and i can't find it.
Main2Activity:
public class Main2Activity extends AppCompatActivity {
Button next, skip;
private ViewPagerAdapter adapter;
private ViewPager viewPager;
private SliderWalkthrough sliderWalkthrough;
private int[] layouts;
private TextView[] dots;
private LinearLayout dotsLayout;
ViewPager.OnPageChangeListener listener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
addButtonDots(position);
if (position == layouts.length - 1) {
next.setText("GET STARTED");
skip.setVisibility(View.GONE);
} else {
next.setText("NEXT");
skip.setVisibility(View.VISIBLE);
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sliderWalkthrough = new SliderWalkthrough(this);
if (!sliderWalkthrough.Check()) {
sliderWalkthrough.setFirst(false);
Intent intent = new Intent(Main2Activity.this, MainActivity.class);
startActivity(intent);
finish();
}
if (Build.VERSION.SDK_INT >= 21) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
setContentView(R.layout.activity_main2);
viewPager = (ViewPager) findViewById(R.id.id_WalkThroughViewPager);
dotsLayout = (LinearLayout) findViewById(R.id.layout_dots);
layouts = new int[]{R.layout.slider_walkthrough_screen1, R.layout.slider_walkthrough_screen2, R.layout.slider_walkthrough_screen3};
addButtonDots(0);
adapter = new ViewPagerAdapter();
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(listener);
}
private void addButtonDots(int position) {
dots = new TextView[layouts.length];
int[] colorActive = getResources().getIntArray(R.array.active_dot);
int[] colorInactive = getResources().getIntArray(R.array.inactive_dot);
dotsLayout.removeAllViews();
for (int i = 0; i < dots.length; i++) {
dots[i] = new TextView(this);
dots[i].setTextSize(30);
dots[i].setTextColor(colorInactive[position]);
dotsLayout.addView(dots[i]);
}
if (dots.length > 0) {
dots[position].setTextColor(colorActive[position]);
}
}
}
SliderWalkthrough:
public class SliderWalkthrough {
SharedPreferences sharedPreferences;
SharedPreferences.Editor editor;
Context context;
public SliderWalkthrough(Context context) {
this.context = context;
sharedPreferences=context.getSharedPreferences("first",0);
editor=sharedPreferences.edit();
}
public void setFirst(Boolean firstTime){
editor.putBoolean("check",firstTime);
editor.commit();
}
public boolean Check()
{
return sharedPreferences.getBoolean("check",true);
}
}

You need to change the preference value to false once your walk-through is finished otherwise if (!sliderWalkthrough.Check()) { will never be executed and walk-through will be shown everytime
#Override
public void onPageSelected(int position) {
addButtonDots(position);
if (position == layouts.length - 1) {
next.setText("GET STARTED");
skip.setVisibility(View.GONE);
sliderWalkthrough.setFirst(false);
//^^^^^^ add this case
}
else {
next.setText("NEXT");
skip.setVisibility(View.VISIBLE);
}
}
Note : remove sliderWalkthrough.setFirst(false); , no longer required
if (!sliderWalkthrough.Check()) {
Intent intent = new Intent(Main2Activity.this, MainActivity.class);
startActivity(intent);
finish();
}

Related

Viewpager operations triggered on wrong reference

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.

viewpager images swipe

I am using Timertask for scrolling images with viewpager. I need to show all images after that it is automatically move to category wise (no click operation).
public class GalleryActviity extends AppCompatActivity {
Timer timer;
LinearLayout images_lay;
ArrayList<String> arraylist = new ArrayList<String>();
List<String> tempimages = new ArrayList<String>();
ViewPager mPager ;
private static int currentPage = 0
List<String> dealimages = new ArrayList<>();
ArrayList<DetailImage> detail_images = new ArrayList<DetailImage>();
#Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
images_lay =(LinearLayout)findViewById(R.id.images_lay);
mPager = (ViewPager) findViewById(R.id.pager);
Intent in = getIntent();
Log.v("Tag_resid",""+in.getStringExtra("restid"));
String restid = in.getStringExtra("restid");
restaurntrestid(restid);
}
private void restaurntrestid(String restid) {
ServiceClient serviceClient = ServiceUtil.getServiceClient();
serviceClient.restaurntrestid(restid, restidcallback);
}
Callback<JsonObject> restidcallback = new Callback<JsonObject>() {
#Override
public void success(final JsonObject cusinerestaurantsinfo, Response response) {
imagesDeatail(cusinerestaurantsinfo);
}
#Override
public void failure(RetrofitError error) {
}
};
private void imagesDeatail(JsonObject cusinerestaurantsinfo) {
try {
JsonArray restaurant_imagesarray = cusinerestaurantsinfo.get("restaurant_images")
.getAsJsonArray();
for (int i = 0; i < restaurant_imagesarray.size(); i++) {
String url = restaurant_imagesarray.get(i).getAsJsonObject().get("url").getAsString();
String type = restaurant_imagesarray.get(i).getAsJsonObject().get("type").getAsString();
if(!arraylist.contains(type)){
arraylist.add(type);
// type means category like food, menu, logo...etc(dynamic data)
}
dealimages.add(url);
DetailImage detail = new DetailImage();
detail.setType(type);
detail.setUrl(url);
detail_images.add(detail);
}
mPager.setAdapter(new DealAdapter(GalleryActviity.this, dealimages));
imageRotator(1);
imageshow();
} catch (Exception e) {
e.printStackTrace();
}
}
public void imageRotator(int seconds) {
currentPage = 0;
timer = new Timer();
timer.scheduleAtFixedRate(new ImageRotateTask(), 0, seconds * 3000);
}
class ImageRotateTask extends TimerTask {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
if (currentPage == dealimages.size() ) {
timer.cancel();
//Something here
}
else {
mPager.setCurrentItem(currentPage++, true);
}
}
});
}
}
private void imageshow(){
for(int i = 0; i < arraylist.size(); i++) {
final Button txtview = new Button(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
layoutParams.setMargins(0, 0, 0, 0);
if(i == 0){
txtview.setText("All");
txtview.setBackgroundColor(getResources().getColor(R.color.navigationBarwhite));
txtview.setTextColor(getResources().getColor(R.color.colorPrimary));
}
else {
txtview.setText(arraylist.get(i));
txtview.setBackgroundColor(getResources().getColor(R.color.navigationBarwhite));
txtview.setTextColor(getResources().getColor(R.color.navigationBarColor));
}
txtview.setLayoutParams(layoutParams);
txtview.setTextSize(12);
txtview.setAllCaps(false);
txtview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!txtview.getText().toString().equalsIgnoreCase("All")){
//image_display(txtview.getText().toString().trim());
txtview.setBackgroundColor(getResources().getColor(R.color.navigationBarwhite));
txtview.setTextColor(getResources().getColor(R.color.colorPrimary));
}
else if(txtview.getText().toString().equalsIgnoreCase("All")){
imageRotator(1);
mPager.setAdapter(new DealAdapter(GalleryActviity.this, dealimages));
}
}
});
images_lay.addView(txtview);
}
}
}
Here i am showing all the images in "ALL" section. how to show the remain images of every catgory. I added my screenshot which will show the images . "ALL" means every category type image will showing in this section.
Here i can showing all images in "ALL" Section, now how to move to automatically show the images based on category.

How to make 500 Questions Quiz in android with single activity?

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();
}
}

FragmentTabHost Fragment Adapters Are Empty Upon Returning To Tab, Fragment/Views Remain

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.

The value of the variable has been suddenly set to 0

I'm doing an activity to measure how long it takes a person to do an exercise, but it has a bug that I couldn't resolve yet...
The TrainingFragment shows a list of exercises that the user can click and then my ExerciseActivity is launched and runs until the variable "remainingsSets" is setted to 0.
When I click in the first time at any exercise, everything works fine, the ExerciseActivity works correctly end return to the TrainingFragment. But then, if I try to click in another exercise, the ExerciseActivity is just closed.
In my debug, I could see that the variable "remainingSets" comes with it's right value (remainingSets = getIntent().getIntExtra("remaining_sets", 3)), but when the startButton is clicked, I don't know why the variable "remainingSets" is setted to 0 and then the activity is closed because this condition: if (remainingSets > 0){...}.
Here is my TrainingFragment:
public class TrainingFragment extends Fragment {
private final static int START_EXERCISE = 1;
private Training training;
private String lastItemClicked;
private String[] values;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Bundle bundle = getArguments();
if (bundle != null) {
training = bundle.getParcelable("training");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return (ScrollView) inflater.inflate(R.layout.template_exercises, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LinearLayout exercisesContainer = (LinearLayout) getView().findViewById(R.id.exercises);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
List<Exercise> exercises = training.getExercises();
values = new String[exercises.size()];
if (savedInstanceState != null) {
values = savedInstanceState.getStringArray("values");
}
for (int i = 0; i < exercises.size(); i++) {
final View exerciseView = inflater.inflate(R.layout.template_exercise, null);
exerciseView.setTag(String.valueOf(i));
TextView remainingSets = (TextView) exerciseView.findViewById(R.id.remaining_sets);
if (savedInstanceState != null) {
remainingSets.setText(values[i]);
} else {
String sets = exercises.get(i).getSets();
remainingSets.setText(sets);
values[i] = sets;
}
exerciseView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ExerciseActivity.class);
intent.putExtra("remaining_sets",
Integer.valueOf(((TextView) v.findViewById(R.id.remaining_sets)).getText().toString()));
lastItemClicked = v.getTag().toString();
startActivityForResult(intent, START_EXERCISE);
}
});
exercisesContainer.addView(exerciseView);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArray("values", values);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
View view = ((LinearLayout) getView().findViewById(R.id.exercises)).findViewWithTag(lastItemClicked);
if (requestCode == START_EXERCISE) {
if (resultCode == Activity.RESULT_OK) { // the exercise had been
// finished.
((TextView) view.findViewById(R.id.remaining_sets)).setText("0");
view.setClickable(false);
values[Integer.valueOf(lastItemClicked)] = "0";
} else if (resultCode == Activity.RESULT_CANCELED) {
String remainingSets = data.getStringExtra("remaining_sets");
((TextView) view.findViewById(R.id.remaining_sets)).setText(remainingSets);
values[Integer.valueOf(lastItemClicked)] = remainingSets;
}
}
}
}
My ExerciseActivity:
public class ExerciseActivity extends Activity {
private Chronometer chronometer;
private TextView timer;
private Button startButton;
private Button endButton;
private int remainingSets;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
ExerciseEvents.addExerciseListener(new PopupExerciseListener());
chronometer = (Chronometer) findViewById(R.id.exercise_doing_timer);
timer = (TextView) findViewById(R.id.timer);
startButton = (Button) findViewById(R.id.start_exercise);
startButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ExerciseEvents.onExerciseBegin();
}
});
endButton = (Button) findViewById(R.id.end_exercise);
endButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ExerciseEvents.onExerciseRest();
}
});
}
#Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("remaining_sets", String.valueOf(remainingSets));
setResult(RESULT_CANCELED, intent);
super.onBackPressed();
}
public class PopupExerciseListener implements ExerciseListener {
public PopupExerciseListener() {
remainingSets = getIntent().getIntExtra("remaining_sets", 3);
}
#Override
public void onExerciseBegin() {
if (remainingSets > 0) {
chronometer.setVisibility(View.VISIBLE);
timer.setVisibility(View.GONE);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.start();
startButton.setVisibility(View.GONE);
endButton.setVisibility(View.VISIBLE);
} else {
ExerciseEvents.onExerciseFinish();
}
}
#Override
public void onExerciseFinish() {
setResult(RESULT_OK);
finish();
}
#Override
public void onExerciseRest() {
chronometer.setVisibility(View.GONE);
endButton.setVisibility(View.GONE);
timer.setVisibility(View.VISIBLE);
long restTime = getIntent().getLongExtra("time_to_rest", 60) * 1000;
new CountDownTimer(restTime, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timer.setText(String.valueOf(millisUntilFinished / 1000));
}
#Override
public void onFinish() {
ExerciseEvents.onExerciseBegin();
}
}.start();
remainingSets--;
}
}
}
And my ExerciseEvents:
public class ExerciseEvents {
private static LinkedList<ExerciseListener> mExerciseListeners = new LinkedList<ExerciseListener>();
public static void addExerciseListener(ExerciseListener listener) {
mExerciseListeners.add(listener);
}
public static void removeExerciseListener(String listener) {
mExerciseListeners.remove(listener);
}
public static void onExerciseBegin() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseBegin();
}
}
public static void onExerciseRest() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseRest();
}
}
public static void onExerciseFinish() {
for (ExerciseListener l : mExerciseListeners) {
l.onExerciseFinish();
}
}
public static interface ExerciseListener {
public void onExerciseBegin();
public void onExerciseRest();
public void onExerciseFinish();
}
}
Could anyone give me any help?
After you updated your code, I see you have a big memory leak in your code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise);
ExerciseEvents.addExerciseListener(new PopupExerciseListener());
....
}
The call ExerciseEvents.addExerciseListener(new PopupExerciseListener()) adds a new PopupExerciseListener to a static/global list: ExcerciseEvents.mExerciseListeners. Since the class PopupExerciseListener is an inner-class, it implicitly holds a reference to its enclosing ExcerciseActivity. This mean your code is holding on to each instance of ExcerciseActivity forever. Not good.
This may also explain the weird behavior you see. When one of the onExcersizeXXX() methods is called, it will call all ExcerciseListeners in the linked-list, the ones from previous screens and the current one.
Try this in your ExcerciseActivity.java:
....
ExerciseListener mExerciseListener;
....
#Override
protected void onCreate(Bundle savedInstanceState) {
....
....
mExerciseListener = new PopupExerciseListener()
ExerciseEvents.addExerciseListener(mExerciseListener);
....
....
}
#Override
protected void onDestroy() {
ExerciseEvents.removeExerciseListener(mExerciseListener);
super.onDestroy();
}
....
In onDestroy, you deregister your listener, preventing a memory leak and preventing odd multiple callbacks to PopupExerciseListeners that are attached to activities that no longer exist.

Categories

Resources