I have a ListView in my activity.On clicking on the list item it invokes another activity.In that activity I have implemented ViewPager and fragments.
When it loads first time onResume() ,onCreate() and onCreateView() method called twice, if I clicks on first list item. (i.e. it loads first and second fragment view)
when I click on the any other List fragment except first then it calls onResume() ,onCreate() and onCreateView() methods three times (i.e. It loads previous and after and click view )
It is absoutely fine but I have google analytics code with which I have to track only current page so where I can put this code to load for only current page
My question is my googleAnalytics code tracs three or two pages at first time even user doesnot gone through those pages how to avoid this ?
My code is as below for fragment
public class MainListActivity extends Activity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate()");
CustomFragmentPagerAdapter adapter = new CustomFragmentPagerAdapter();
viewPager.setAdapter(adapter);
}
}
//code for fragment adapter
public class CustomFragmentPagerAdapter extends FragmentPagerAdapter {
public CustomFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
CustomFragment customFragment = new CustomFragment();
arrayList.add(customFragment);
return customFragment;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return arrayList.size();
}
}
//code for fragment
public class CustomFragment extends Fragment{
public CustomFragment() {
super();
}
#Override
public void onResume() {
super.onResume();
Log.v(TAG, "onCreate -Resume");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "onCreate");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.v(TAG, "onCreateView");
return myAnyView;
}
}
The problem is that the onResume() method is called for all your fragments, that is including the invisible ones.
Check gorn's answer here:
How to determine when Fragment becomes visible in ViewPager
You have to override
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// Your logic
}
and do your logic in there.
Related
I have an Activity with three tabs and three Fragments. First Fragment shows the list of song titles and the second tab displays the selected song. The details of the songs is coming from a database.
I am implementing SearchView feature so that whatever search text user enters, only those songs should be displayed in the index.
This is exactly like the way phone book work in our devices.
I'm not able to understand how to refresh the first Fragment when the search query changes.
I'm basically looking for the method that I can call to refresh the first Fragment.
Got my answer here Android refresh a fragment list from its parent activity as suggested by #Prem. Works perfectly fine for me.
Its is achievable by making an interface
MainActivity.java
public class MainActivity extends Activity {
public FragmentRefreshListener getFragmentRefreshListener() {
return fragmentRefreshListener;
}
public void setFragmentRefreshListener(FragmentRefreshListener fragmentRefreshListener) {
this.fragmentRefreshListener = fragmentRefreshListener;
}
private FragmentRefreshListener fragmentRefreshListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button)findViewById(R.id.btnRefreshFragment);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(getFragmentRefreshListener()!=null){
getFragmentRefreshListener().onRefresh();
}
}
});
}
public interface FragmentRefreshListener{
void onRefresh();
}}
MyFragment.java
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = null; // some view
/// Your Code
((MainActivity)getActivity()).setFragmentRefreshListener(new MainActivity.FragmentRefreshListener() {
#Override
public void onRefresh() {
// Refresh Your Fragment
}
});
return v;
}}
Below is the one way, you can easily do it. You just have to save the fragment instance. That's all.
private class ViewPagerAdapter extends FragmentStatePagerAdapter {
private SparseArray<Fragment> array = new SparseArray<>();
ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
array.setValueAt(position, myFragment);
return myFragment;
}
#Override
public int getCount() {
return 3;
}
public SparseArray<Fragment> getFragmentArray() {
return array;
}
}
Then from your activity, you can get all viewpager fragment easily from adapter instance.
MyFragment fragment = (MyFragment) adapter.getFragmentArray().get(0); // get first fragment and casting it to your origin fragment
Then create a method on that fragment. Call like below:
fragment.myFragmentMethod(String myData){}
Have a nice day!
I am trying to call the functions frag.updateButtons() etc from within GameScreen (Main Activity) as ten times a second, the game cycles through these things and updates the variables accordingly.
The code is as it currently is. The frag.*** functions work when it is set up as a fragment, but now that I am wanting to use it as viewPager, it keeps having the following error:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.support.v4.app.FragmentActivity.findViewById(int)' on a null object reference
I am fairly new to programming and Android code, and clearly don't entirely understand fragments and viewPager etc, so any help here would be very much appreciated.
I have not included the whole code, just the code that I think is relevant to the problem. If you need more code or info, please ask me and I'll get you what you need.
Thank you
public class GameScreen extends FragmentActivity implements GameScreenFragment.FragInterface{
ViewPager mViewPager;
GameScreenFragment frag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_screen);
mViewPager = (ViewPager) findViewById(R.id.bottomFragment);
/** set the adapter for ViewPager */
mViewPager.setAdapter(new SamplePagerAdapter(getSupportFragmentManager()));
startRepeatingTask();
//the code here calls the mainLoop() function 10 times a second
}
}
//for the fragment functions
public void displayCompany(String companyName){}
public void displayCompanyIncome(){}
public void checkTeamImage(){}
public void getCostOfEmployees(){}
public void updateButtons(){}
public void mainLoop(){
//display company name and company income in fragment
frag = (GameScreenFragment) getSupportFragmentManager().findFragmentById(R.id.bottomFragment);
frag.updateButtons();
frag.displayCompanyIncome();
frag.getCostOfEmployees();
frag.displayCompany(Global.companyName[Global.companyNumber]);
//updates the picture for that company
frag.checkTeamImage();
}
public class SamplePagerAdapter extends FragmentPagerAdapter {
public SamplePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
/** Show a Fragment based on the position of the current screen */
Global.companyNumber = position;
return new GameScreenFragment();
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
}
}
and then in the fragment whose ID in the .xml is bottomFragment
public class GameScreenFragment extends Fragment {
FragInterface fragStuff;
public interface FragInterface {
void displayCompany(String companyName);
void displayCompanyIncome();
void checkTeamImage();
void getCostOfEmployees();
void displayCompanyName();
void updateButtons();
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState){
View view = inflater.inflate(R.layout.game_screen_fragment, container, false);
//other code here
return view;
}
}
I had created tabview with swipe using Fragments and FragmentPagerAdapter. In the fragment's hosting activity, I had added a fragment and that fragment shows tabview using TabHost. 1st tab has a listview that displays data from DB using CursorLoader and the 2nd one is mapView.
Everything works fine in portrait mode.
Problem occurs in following case:
User is using app in landscape mode. He opened tabbed view screen. Data is displayed in the listview from the cursor loader. Mapview is also displayed in the second tab. So far everything is working as required.
He left the app as is.(Means, he did not pressed back button, home button or switched to another app)
Screen went off after some time.
When user unlocks the device, my app's tabbed view will be visible again. But,now listview does not show any data and mapview also disappeared.
ClientListFragment
public class ClientListFragment extends SwipeRefreshListFragment {
private static final String TAG = "ClientListFragment";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate");
setHasOptionsMenu(true);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setColorScheme(R.color.gplus_color_1, R.color.gplus_color_2,
R.color.gplus_color_3, R.color.gplus_color_4);
}
#Override
public void onResume() {
super.onResume();
Log.e(TAG, "onResume");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.e(TAG, "onActivityCreated");
}
#Override
public void onPause() {
// Log.i(TAG, "onPause");
super.onPause();
}
#Override
public void onStop() {
super.onStop();
Log.e(TAG, "onStop");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
}
}
Map Fragment
public class ClientMapFragment extends Fragment {
private static final String TAG = "ClientMapFragment";
private GoogleMap googleMap;
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.map_fragment, container, false);
googleMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
googleMap.setMyLocationEnabled(true);
return v;
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onStop() {
super.onStop();
}
#Override
public void onPause() {
super.onPause();
}
}
Activity
public class ClientActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
if (isTablet)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
else
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
setContentView(R.layout.activity_clients);
ClientFragment clientFragment = new ClientFragment();
Bundle bundle = new Bundle();
bundle.putBoolean("ShouldChangeActionBarTitle", true);
clientFragment.setArguments(bundle);
getFragmentManager()
.beginTransaction()
.add(R.id.fragmentContainer, clientFragment,
getResources().getString(R.string.clients_fragment))
.commit();
}
}
FragmentpagerAdapter
public class TabsPagerAdapter extends FragmentStatePagerAdapter {
private static final String TAG = "TabsPagerAdapter";
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
FragmentManager fm;
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
this.fm = fm;
mFragments.add(new ClientListFragment());
mFragments.add(new ClientMapFragment());
}
#Override
public Fragment getItem(int index) {
Log.e(TAG, "getItem");
return mFragments.get(index);
}
#Override
public int getCount() {
return mFragments.size();
}
}
Update 1
So, after doing hours of research I came to a conclusion that, it is problem with fragment's state in the FragmentPagerAdapter. When screen is turned off fragmentpager's saveState is called.. When the device is unlocked again, fragment's will be restored from previous state. I verified that LoaderManager callbacks are called, and data was also fetched from DB. But, didn't appeared on screen.
I didn't even bothered about looking at my activities code at once. Everytime, a new fragment was created in onCreate(). The fix is very simple.
if (savedInstanceState == null) {
Log.e(TAG, "onCreate savedInstanceState == null");
ClientFragment clientFragment = new ClientFragment();
Bundle bundle = new Bundle();
bundle.putBoolean("ShouldChangeActionBarTitle",
shouldChangeActionBarTitle);
clientFragment.setArguments(bundle);
getFragmentManager()
.beginTransaction()
.add(R.id.fragmentContainer, clientFragment,
getResources().getString(R.string.clients_fragment))
.commit();
}
I have an android Activity with swipe navigation (implemented with ViewPager).
public class UberActivity extends FragmentActivity {
ViewPager mViewPager;
protected void onCreate(Bundle savedInstanceState) {
//... some stuff
myfragment1=new MyFragment1();
myfragment2=new MyFragment2();
myfragment3=new MyFragment3();
myfragment4=new MyFragment4();
}
public void onChoiceSelected(){
mViewPager.post(new Runnable(){public void run(){
myfragmen1.update();
myfragmen2.update();
myfragmen3.update();
myfragmen4.update();
}});
}
}
public class Fragment4 extends Fragment {
View v;
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup container,
Bundle savedInstanceState) {
v=layoutInflater.inflate(R.layout.mylayout,container,false);
return v;
}
public void update(){
((TextView)v.findViewById(R.id.textView1)).setText("new text");
}
I will get a NullPointerException on update(), unless I beforehand swipe to it (so that its layout is actually inflated before calling update()).
The problem here is that Fragment4 is instanced but its OnCreateView() is not called. How should I check if OnCreateView() is called? I could put a boolean there, but I don't think this is a best practice...
Just add an if-statement around 'v', checking if it is null or not.
public void update(){
if (v != null) {
((TextView)v.findViewById(R.id.textView1)).setText("new text");
}
}
I have a Sherlock Tab Navigation implemented as the following two classes. Class Dashboard is the main activity. Class DashboardContacts represents one of the tab's fragment.
I am loading HTTP data that gets loaded in a while and when it loads I need the list view in DashboardContacts to reflect the changes brought in from Server and refresh the ListView from blank to filled list. For this i'm calling notifyDataSetChanged method through refresh method in DashboardContacts, but no change relects in ListView until I change the tabs.
public class Dashboard extends SherlockFragmentActivity {
private DashboardContacts contactsTab=new DashboardContacts();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dashboard);
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab = getSupportActionBar().newTab();
tab.setText(getResources().getStringArray(R.array.dashboardTabs)[0]);
tab.setTabListener(new DashboardHome());
getSupportActionBar().addTab(tab);
ActionBar.Tab tab2 = getSupportActionBar().newTab();
tab2.setText(getResources().getStringArray(R.array.dashboardTabs)[1]);
tab2.setTabListener(contactsTab);
getSupportActionBar().addTab(tab2);
//CALLS ASYNCLOADER HERE TO LOAD HTTP DATA
}
private void httpSuccessMethod() {
//Does some work and then calls:
contactsTab.refresh(datasource.getAllContacts());
}
Here is the DashboardContacts class layout:
public class DashboardContacts extends SherlockListFragment implements ActionBar.TabListener{
private UserListAdapter listAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
listAdapter=new UserListAdapter(container.getContext(), ApplicationState.getInstance(container.getContext()).getUserCache());
setListAdapter(listAdapter);
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onTabSelected(Tab tab,android.support.v4.app.FragmentTransaction ft) {
ft.replace(android.R.id.content, this,"contacts");
ft.attach(this);
}
#Override
public void onTabUnselected(Tab tab,android.support.v4.app.FragmentTransaction ft) {
ft.detach(this);
}
#Override
public void onTabReselected(Tab tab,android.support.v4.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
}
public void refresh(List<User> list) {
if(this.listAdapter != null) {
this.listAdapter.setList(list);
this.listAdapter.notifyDataSetChanged();
}
}
The refresh method in the custom list adapter looks like, so I am actually changing the data there too:
public void refresh(List<User> list) {
if(this.listAdapter != null) {
this.listAdapter.setList(list);
this.listAdapter.notifyDataSetChanged();
}
I think this is something I didn't implement, so I did it now and solved the issue:
public void setList(List<ExpensePool> list) {
clear();
addAll(list);
notifyDataSetChanged();
}