I created a new Tabbed Activity from Android Studio. This gives me an activity and a fragment. I want the tabs to go through a list that is in some MyData db object instanciated in the onCreate method (so far so good).
I put in the tabs layout fragment_tabbed.xml a button and a viewtext that I would like to change accordingly to the elements of y list when browsing. The button is supposed to do some action such as db.delete(id).
My problem is that I don't know how to attach this action to the button and update it as the tab on display changes. I tried in the onCreateView but it complains that "Tabbed.this.db cannot be referenced from a static context". I tried to just remove the "static" but I the editor complains that "fragment inner class should be static".
I got the trick of using an argument bundle to pass my text data (which is not really convenient by the way, can't I get my data from my db object?), but not how to deal with the button's action as I want to act on my db object. How can I get around this? I tried to update the whole button's action but I suppose I could just update some argument containing just the id that I could update with the same trick as the text, and have it passed as some argument by a more general onClick action, but I lack experience and could use some hints.
The following code is mostly what was generated by Android Studio, with my attemp to add listener on the button.
public class Tabbed extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
private MyData db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabbed);
db = new MyData();
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_tabbed, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_tabbed, container, false);
TextView textView = (TextView) rootView.findViewById(R.id.section_label);
textView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER)));
Button buttonDelete = (Button) rootView.findViewById(R.id.b_del);
buttonDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick (View view) {
Tabbed.this.db.delete(
getArguments().getInt(ARG_SECTION_NUMBER));
}
});
return rootView;
}
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1);
}
#Override
public int getCount() {
return 3;
}
}
}
Because your inner fragment is declared as public static class, instances of this class do not hold a reference to the outer class. As such, you can't get a reference to the fragment's activity by writing Tabbed.this.
However, you can get a reference to the activity in a different way. Because your app is simple, you know that all PlaceholderFragment instances will be running inside of Tabbed activity instances. So you can just write this:
#Override
public void onClick (View view) {
Tabbed tabbed = (Tabbed) view.getContext();
tabbed.db.delete(getArguments().getInt(ARG_SECTION_NUMBER));
}
Related
I've created activity from TabbedActivity template (in Android Studio):
This template uses Fragment and FragmentPagerAdapter to handle tabs.
This is code of two classes, PlaceholderFragment extends Fragment, and SectionsPagerAdapter extends FragmentPagerAdapter:
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list_view, container, false);
int scnum = getArguments().getInt(ARG_SECTION_NUMBER);
final ListView listView = (ListView) rootView.findViewById(R.id.products_list);
// here refresh my listView trough internet
return rootView;
}
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1);
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
}
In onCreateView method I refresh my ListView. This method is called when i switch tabs.
But I need to refresh ListView not when user switch tabs, but:
1. every 10 seconds
2. when user comes back to this activity (onRestart() method is called)
I have no idea how to access my ListView outside onCreateView method.
I've already tried many solutions from the internet to call onCreateView method from onRestart method, and just to access my ListView from onRestart(). None of them worked.
Globally in Activity class I have an instance of SectionsPagerAdapter and ViewPager:
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
They are initalized in onCreate by this way:
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
I think, there are 2 possible solutions, access my Fragment's view or just recall onCreateView.
I've already tried to do:
This one just doesn't work:
#Override
protected void onRestart() {
super.onRestart();
mSectionsPagerAdapter.notifyDataSetChanged();
}
This one crashes app because of NullPointerException:
#Override
protected void onRestart() {
super.onRestart();
Fragment f = mSectionsPagerAdapter.getItem(0); // tab with my list view is first tab. ( getItem(1) also does not work )
View v = f.getView(); // v is null here, however f isn't.
final ListView listView = v.findViewById(R.id.products_list); // v is null, NullPointerException is thrown.
// here refresh my listView trough internet
}
EDIT:
Since I started using Kotlin, answer based on that language will be also accepted. However, I am new to Kotlin, so more detailed answer would be needed then.
So you have a list in a Fragment that is inside a ViewPager. Ther are a few ways to solve your problem, I'd suggest you use the first one, because it is the simplest.
Fragment have lifecycle callbacks that are triggered together with lifecycle callbacks of Activity that contains that fragment. It covers most of the methods, but unfortunately not the onRestart that you are looking for. But that's not a big problem. Actually, you almost never need onRestart because you have onStart method, that method is accessible from both Fragments and Activities. It is called every time activity is restarted + the very first time activity is started. And as we can see it is exactly what you need. So to have your list updated every time, just remove the update code from the onCreate method and put it into onStart method of the Fragment.
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
private ListView listView = null;
public PlaceholderFragment() {
}
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list_view, container, false);
int scnum = getArguments().getInt(ARG_SECTION_NUMBER);
listView = (ListView) rootView.findViewById(R.id.products_list);
return rootView;
}
#Override
public void onStart() {
// here refresh your listView trough internet using the listView class field
}
}
Another option would be to get a reference to your fragment inside the activity. The solution I usually use is to retain a reference to the fragment inside the adapter. It is similar to the second option in your question. The only problem with your solution is that mSectionsPagerAdapter.getItem(0); always create a new fragment, while you need to get a reference to already existing fragment.
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private PlaceholderFragment fragmentZero = null;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
PlaceholderFragment tabFragment = PlaceholderFragment.newInstance(position + 1);
if (position == 0) {
fragmentZero = tabFragment;
}
return tabFragment;
}
#Override
public int getCount() {
return 3;
}
public PlaceholderFragment getFragmentZero() {
return fragmentZero;
}
}
You also need to move your list update logic to a separate method in the PlaceholderFragment:
private ListView listView = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list_view, container, false);
int scnum = getArguments().getInt(ARG_SECTION_NUMBER);
listView = (ListView) rootView.findViewById(R.id.products_list);
refreshListView();
return rootView;
}
public void refreshListView() {
// here refresh your listView trough internet
}
At this point you can do:
#Override
protected void onRestart() {
super.onRestart();
Fragment listFragment = mSectionsPagerAdapter.getFragmentZero();
listFragment.refreshListView();
}
Whenever you have a fragment inside an activity, in a ViewPager or not, you can get a reference to the fragment using FragmentManager. Check this for details regarding the ViewPager option.
All the code above is rather straightforward and would not require any special Kotlin idioms if you'd prefer to implement it in Kotlin. You can start with converting your classes in the android studio. To do it:
Navigate to your java class
Press Control + Shift + A on Windows or Command + Shift + A on Mac
Search for Convert Java File to Kotlin File
Apply
And you are good to go with the Kotlin code of given classes. The only thing that might be quite different from java is handling ARG_SECTION_NUMBER since Kotlin does not have static fields and use Companion Objects instead.
I created a tabbed activity called UserProfile.java. As many of you know, this kind of activity comes with a built-in class called PlaceholderFragment which is basically where the magic happens. Mine looks as follows:
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Some code related to database queries irrelevant to this question...
if (getArguments().getInt(ARG_SECTION_NUMBER) == 1) {
View profileView = inflater.inflate(
R.layout.fragment_user_profile_data,
container,
false
);
// Here's some code intended to get edittext's values irrelevant to this question...
final Button saveProfile = (Button) profileView.findViewById(R.id.profile_save_data);
saveProfile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
UpdateProfileForm upf = new UpdateProfileForm(
userName.getText().toString(),
userLastName.getText().toString(),
userID.getText().toString(),
userPhone.getText().toString(),
userEmail.getText().toString(),
userAddress.getText().toString()
);
new UpdateProfile().execute(upf);
view.setVisibility(View.GONE);
}
});
return profileView;
} else if (getArguments().getInt(ARG_SECTION_NUMBER) == 2) {
View profileView = inflater.inflate(R.layout.another_fragment, container, false);
return profileView;
} else {
View profileView = inflater.inflate(R.layout.fragment_user_profile_data, container, false);
return profileView;
}
}
}
As you can see, I have a form fragment called fragment_user_profile_data where I get user's data, a UpdateProfileForm class to store it and pass it to an AsyncTask called UpdateProfile used to update the user information in server side when clicking the saveProfile button.
However, if a try that line
new UpdateProfile().execute(upf);
an
'com.example.UserProfile.this' cannot be referenced from a static context
error will be shown by Android Studio. I was told either to take the "static" property off from the PlaceholderFragment class or to make my AsyncTask static, but neither of them work.
I'm stuck in this so any help would be appreciated!
So, basically what I was doing was wrong since I was using a single fragment (PlaceholderFragment) for three separate responsibilities, as #cricket_007 mentioned in his comment to my question.
I did this because the only TabbedActivity tutorial I found uses it.
Basically, when working with a TabbedActivity, you don't need the PlaceholderFragment so you can easily get rid of it. Now, in the getItem method of the SectionsPagerAdapter class generated within the activity, replace the following line
return PlaceholderFragment.newInstance(position + 1);
with a switch statement for the position argument and return an instance of the appropriate fragment. i.e.:
public Fragment getItem(int position) {
switch (position) {
case 0:
UserProfileData tab1 = new UserProfileData();
return tab1;
case 1:
UserProfileCollections tab2 = new UserProfileCollections();
return tab2;
case 2:
UserProfileBalance tab3 = new UserProfileBalance();
return tab3;
default:
return null;
}
}
Finally, declare the AsyncTask and the form class into the Fragment class and set the EditTexts' values and button's functionality within the Fragment's onCreateView method, then inflate it and return it.
I hope this answer helps given the lack of samples about this Activity. Thank you for your answers anyways!
You can't call MyActivity.this from static method.
Here's a workaround.
Declare a variable in your Activity/Fragment like this:
private static Activity activity;
Then in your onCreate():
activity = this;
// OR
activity = getActivity(); // if you are in fragment
And then, in your UpdateProfile() AsyncTask method, call it like this:
activity.someMethod();
Remove static keyword from Fragment.
public static class PlaceholderFragment extends Fragment
and Move UpdateProfile AsyncTask in separate class. Now it seems like an Inner class of another fragment.
I am having trouble compiling this app in Android Studio. In Eclipse I have no issues. I have no clue what is the issue. There appears to be an issue with my call at getActionBar() method. Error states that Call requires API 14 (current min is 8). I know I downloaded all updates for SDK. I'm lost please help. Thank you all.
public class HomeActivity extends FragmentActivity implements ActionBar.TabListener {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide fragments for each of the
* three primary sections of the app. We use a {#link android.support.v4.app.FragmentPagerAdapter}
* derivative, which will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
AppSectionsPagerAdapter mAppSectionsPagerAdapter;
/**
* The {#link ViewPager} that will display the three primary sections of the app, one at a
* time.
*/
ViewPager mViewPager;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Create the adapter that will return a fragment for each of the three primary sections
// of the app.
mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager());
// Set up the action bar.
final ActionBar actionBar = getActionBar();
// Specify that the Home/Up button should not be enabled, since there is no hierarchical
// parent.
actionBar.setHomeButtonEnabled(false);
// Specify that we will be displaying tabs in the action bar.
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set up the ViewPager, attaching the adapter and setting up a listener for when the
// user swipes between sections.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// When swiping between different app sections, select the corresponding tab.
// We can also use ActionBar.Tab#select() to do this if we have a reference to the
// Tab.
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by the adapter.
// Also specify this Activity object, which implements the TabListener interface, as the
// listener for when this tab is selected.
actionBar.addTab(
actionBar.newTab()
.setText(mAppSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to one of the primary
* sections of the app.
*/
public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {
public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
// The first section of the app is the most interesting -- it offers
// a launchpad into the other demonstrations in this example application.
return new LaunchpadSectionFragment();
default:
// The other sections of the app are dummy placeholders.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
fragment.setArguments(args);
return fragment;
}
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
return "Section " + (position + 1);
}
}
/**
* A fragment that launches other parts of the demo application.
*/
public static class LaunchpadSectionFragment extends Fragment {
public MediaPlayer sound;
public AudioManager audioM;
public SoundPool spool;
public int soundID;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_section_launchpad, container, false);
sound = MediaPlayer.create(getActivity(), R.raw._main_select);
spool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
soundID = spool.load(getActivity(), R.raw._main_select, 1);
// Demonstration of a collection-browsing activity.
rootView.findViewById(R.id.demo_collection_button)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sound.start();
//Sound();
Intent intent = new Intent(getActivity(), MenuActivity.class);
startActivity(intent);
}
});
// Demonstration of navigating to external activities.
rootView.findViewById(R.id.demo_external_activity)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Create an intent that asks the user to pick a photo, but using
// FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, ensures that relaunching
// the application from the device home screen does not return
// to the external activity.
Intent externalActivityIntent = new Intent(Intent.ACTION_PICK);
externalActivityIntent.setType("image/*");
externalActivityIntent.addFlags(
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
startActivity(externalActivityIntent);
}
});
return rootView;
}
public void Sound(){
AudioManager audioM = (AudioManager) getActivity().getSystemService(AUDIO_SERVICE);
float volume = (float) audioM.getStreamVolume(AudioManager.STREAM_MUSIC);
spool.play(soundID, volume, volume, 1, 0, 1f);
}
}
/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
*/
public static class DummySectionFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_section_dummy, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
getString(R.string.dummy_section_text, args.getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
}
Log:
Execution failed for task ':app:dexDebug'.
com.android.ide.common.internal.LoggedErrorException: Failed to run command:
/Users/randolphgordon/adt-bundle-mac-x86_64-20131030/sdk/build-tools/19.0.2/dx --dex --output /Users/randolphgordon/Dropbox/_workspace/NYCTLCHACKPREP/app/build/dex/debug /Users/randolphgordon/Dropbox/_workspace/NYCTLCHACKPREP/app/build/classes/debug /Users/randolphgordon/Dropbox/_workspace/NYCTLCHACKPREP/app/build/dependency-cache/debug /Users/randolphgordon/Dropbox/_workspace/NYCTLCHACKPREP/app/build/pre-dexed/debug/android-support-v4-46e47f42317d6d3bf8d7ae02b23fb005cc7afb47.jar /Users/randolphgordon/Dropbox/_workspace/NYCTLCHACKPREP/app/build/pre-dexed/debug/classes-4a5ca97410ee19b747521fb500fab3687b1a037c.jar /Users/randolphgordon/Dropbox/_workspace/NYCTLCHACKPREP/app/build/pre-dexed/debug/support-v4-19.0.1-0d7b819b7b894911a3c8ca1b4399345922bb3696.jar
Error Code:
2
Output:
UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Multiple dex files define Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat$AccessibilityServiceInfoVersionImpl;
at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:594)
at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:552)
at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:533)
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:170)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
at com.android.dx.command.dexer.Main.run(Main.java:230)
at com.android.dx.command.dexer.Main.main(Main.java:199)
at com.android.dx.command.Main.main(Main.java:103)
You have two copies of android-support-v4.jar in your project. Remove one and build again.
I am referring to this tutorial for making simple tabs in Android.
MainActivity.java
public class MainActivity extends Activity {
// Declare Tab Variable
ActionBar.Tab Tab1, Tab2, Tab3;
Fragment fragmentTab1 = new FragmentTab1();
Fragment fragmentTab2 = new FragmentTab2();
Fragment fragmentTab3 = new FragmentTab3();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getActionBar();
// Hide Actionbar Icon
actionBar.setDisplayShowHomeEnabled(false);
// Hide Actionbar Title
actionBar.setDisplayShowTitleEnabled(false);
// Create Actionbar Tabs
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set Tab Icon and Titles
Tab1 = actionBar.newTab().setIcon(R.drawable.tab1);
Tab2 = actionBar.newTab().setText("Tab2");
Tab3 = actionBar.newTab().setText("Tab3");
// Set Tab Listeners
Tab1.setTabListener(new TabListener(fragmentTab1));
Tab2.setTabListener(new TabListener(fragmentTab2));
Tab3.setTabListener(new TabListener(fragmentTab3));
// Add tabs to actionbar
actionBar.addTab(Tab1);
actionBar.addTab(Tab2);
actionBar.addTab(Tab3);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
fragmenttab1.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/Fragment1" />
</RelativeLayout>
Similarly other XML & Java files.
The output is:
Clearly tabs are not uniformly distributed, since empty space is left on right hand side, all seems to be pushed to left corner.
How to make this happen?
Try this code:-
Main Activity
public class MainActivity extends FragmentActivity implements
ActionBar.TabListener {
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the primary sections of the app.
*/
public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {
public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 4;
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
// The first section of the app is the most interesting -- it
// offers
// a launchpad into the other demonstrations in this example
// application.
i++;
return new LaunchpadSectionFragment();
case 1:
// The first section of the app is the most interesting -- it
// offers
// a launchpad into the other demonstrations in this example
// application.
i++;
return new LaunchpadSectionFragment();
case 2:
// The first section of the app is the most interesting -- it
// offers
// a launchpad into the other demonstrations in this example
// application.
i++;
return new LaunchpadSectionFragment();
case 3:
// The first section of the app is the most interesting -- it
// offers
// a launchpad into the other demonstrations in this example
// application.
i++;
return new LaunchpadSectionFragment();
case 4:
// The first section of the app is the most interesting -- it
// offers
// a launchpad into the other demonstrations in this example
// application.
i++;
return new LaunchpadSectionFragment();
default:
// The other sections of the app are dummy placeholders.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
fragment.setArguments(args);
return fragment;
}
}
#Override
public CharSequence getPageTitle(int position) {
String name = null;
switch (position) {
case 0:
name = "School Info";
break;
case 1:
name = "Picture (s)";
break;
default:
name = "Group";
break;
}
return name;
}
}
/**
* A dummy fragment representing a section of the app, but that simply
* displays dummy text.
*/
public static class DummySectionFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_section_dummy,
container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1))
.setText(getString(R.string.dummy_section_text,
args.getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
/**
* A fragment that launches other parts of the demo application.
*/
public static class LaunchpadSectionFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment_section_launchpad, container, false);
// Demonstration of a collection-browsing activity.
rootView.findViewById(R.id.demo_collection_button)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(),
CollectionDemoActivity.class);
startActivity(intent);
}
});
// Demonstration of navigating to external activities.
rootView.findViewById(R.id.demo_external_activity)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Create an intent that asks the user to pick a
// photo, but using
// FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, ensures that
// relaunching
// the application from the device home screen does
// not return
// to the external activity.
// Intent externalActivityIntent = new Intent(
// Intent.ACTION_PICK);
// externalActivityIntent.setType("image/*");
// externalActivityIntent
// .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
// startActivity(externalActivityIntent);
System.exit(0);
}
});
return rootView;
}
}
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the three primary sections of the app. We use a
* {#link android.support.v4.app.FragmentPagerAdapter} derivative, which
* will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a
* {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
AppSectionsPagerAdapter mAppSectionsPagerAdapter;
/**
* The {#link ViewPager} that will display the three primary sections of the
* app, one at a time.
*/
ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create the adapter that will return a fragment for each of the three
// primary sections
// of the app.
mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(
getSupportFragmentManager());
// Set up the action bar.
final ActionBar actionBar = getActionBar();
// Specify that the Home/Up button should not be enabled, since there is
// no hierarchical
// parent.
actionBar.setHomeButtonEnabled(false);
// Specify that we will be displaying tabs in the action bar.
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set up the ViewPager, attaching the adapter and setting up a listener
// for when the
// user swipes between sections.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager
.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// When swiping between different app sections, select
// the corresponding tab.
// We can also use ActionBar.Tab#select() to do this if
// we have a reference to the
// Tab.
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter.
// Also specify this Activity object, which implements the
// TabListener interface, as the
// listener for when this tab is selected.
actionBar.addTab(actionBar.newTab()
.setText(mAppSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
CollectionDemoActivity
public class CollectionDemoActivity extends FragmentActivity {
/**
* A {#link android.support.v4.app.FragmentStatePagerAdapter} that returns a
* fragment representing an object in the collection.
*/
public static class DemoCollectionPagerAdapter extends
FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
// For this contrived example, we have a 10-object collection.
return 10;
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1); // Our object is
// just an
// integer :-P
fragment.setArguments(args);
return fragment;
}
#Override
public CharSequence getPageTitle(int position) {
return "Q. Set " + (position + 1);
}
}
/**
* A dummy fragment representing a section of the app, but that simply
* displays dummy text.
*/
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "Question Set";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1))
.setText("Q.Set "
+ Integer.toString(args.getInt(ARG_OBJECT)));
return rootView;
}
}
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments representing each object in a collection. We use a
* {#link android.support.v4.app.FragmentStatePagerAdapter} derivative,
* which will destroy and re-create fragments as needed, saving and
* restoring their state in the process. This is important to conserve
* memory and is a best practice when allowing navigation between objects in
* a potentially large collection.
*/
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
/**
* The {#link android.support.v4.view.ViewPager} that will display the
* object collection.
*/
ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection_demo);
// Create an adapter that when requested, will return a fragment
// representing an object in
// the collection.
//
// ViewPager and its adapters use support library fragments, so we must
// use
// getSupportFragmentManager.
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(
getSupportFragmentManager());
// Set up action bar.
final ActionBar actionBar = getActionBar();
// Specify that the Home button should show an "Up" caret, indicating
// that touching the
// button will take the user one step up in the application's hierarchy.
actionBar.setDisplayHomeAsUpEnabled(true);
// Set up the ViewPager, attaching the adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// This is called when the Home (Up) button is pressed in the action
// bar.
// Create a simple intent that starts the hierarchical parent
// activity and
// use NavUtils in the Support Package to ensure proper handling of
// Up.
Intent upIntent = new Intent(this, MainActivity.class);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// This activity is not part of the application's task, so
// create a new task
// with a synthesized back stack.
TaskStackBuilder.from(this)
// If there are ancestor activities, they should be added here.
.addNextIntent(upIntent).startActivities();
finish();
} else {
// This activity is part of the application's task, so simply
// navigate up to the hierarchical parent activity.
NavUtils.navigateUpTo(this, upIntent);
}
return true;
case R.id.menuCancel:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
Please use FragmentActivity instead of Activity, it will be worthy. And refer this documentation, it helps the beginners very well.
http://developer.android.com/guide/topics/ui/actionbar.html
It depends on the emulator - i mean name of the device in the emulator
try other one with different API level
There is no problem with the code
I am studying the code below, but I was able to compile it successfully, my problem is using the code I want to have a series of connected Activities in one tab section. Please give your suggestions and ideas abut this. The whole source came from link. Your help and explanation is greatly appreciated. THanks!
Tab 1
-Activity A -> Activity B -> Activity C
Here: Effective Navigation
MainActivity.java
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide fragments for each of the
* three primary sections of the app. We use a {#link android.support.v4.app.FragmentPagerAdapter}
* derivative, which will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a {#link android.support.v4.app.FragmentStatePagerAdapter}.
*/
AppSectionsPagerAdapter mAppSectionsPagerAdapter;
/**
* The {#link ViewPager} that will display the three primary sections of the app, one at a
* time.
*/
ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create the adapter that will return a fragment for each of the three primary sections
// of the app.
mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager());
// Set up the action bar.
final ActionBar actionBar = getActionBar();
// Specify that the Home/Up button should not be enabled, since there is no hierarchical
// parent.
actionBar.setHomeButtonEnabled(false);
// Specify that we will be displaying tabs in the action bar.
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set up the ViewPager, attaching the adapter and setting up a listener for when the
// user swipes between sections.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// When swiping between different app sections, select the corresponding tab.
// We can also use ActionBar.Tab#select() to do this if we have a reference to the
// Tab.
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by the adapter.
// Also specify this Activity object, which implements the TabListener interface, as the
// listener for when this tab is selected.
actionBar.addTab(
actionBar.newTab()
.setText(mAppSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to one of the primary
* sections of the app.
*/
public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {
public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
// The first section of the app is the most interesting -- it offers
// a launchpad into the other demonstrations in this example application.
return new LaunchpadSectionFragment();
default:
// The other sections of the app are dummy placeholders.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
fragment.setArguments(args);
return fragment;
}
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
return "Section " + (position + 1);
}
}
/**
* A fragment that launches other parts of the demo application.
*/
public static class LaunchpadSectionFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_section_launchpad, container, false);
// Demonstration of a collection-browsing activity.
rootView.findViewById(R.id.demo_collection_button)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), CollectionDemoActivity.class);
startActivity(intent);
}
});
// Demonstration of navigating to external activities.
rootView.findViewById(R.id.demo_external_activity)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Create an intent that asks the user to pick a photo, but using
// FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, ensures that relaunching
// the application from the device home screen does not return
// to the external activity.
Intent externalActivityIntent = new Intent(Intent.ACTION_PICK);
externalActivityIntent.setType("image/*");
externalActivityIntent.addFlags(
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
startActivity(externalActivityIntent);
}
});
return rootView;
}
}
/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
*/
public static class DummySectionFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_section_dummy, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
getString(R.string.dummy_section_text, args.getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
}
CollectionDemoActivity.java
public class CollectionDemoActivity extends FragmentActivity {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide fragments representing
* each object in a collection. We use a {#link android.support.v4.app.FragmentStatePagerAdapter}
* derivative, which will destroy and re-create fragments as needed, saving and restoring their
* state in the process. This is important to conserve memory and is a best practice when
* allowing navigation between objects in a potentially large collection.
*/
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
/**
* The {#link android.support.v4.view.ViewPager} that will display the object collection.
*/
ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection_demo);
// Create an adapter that when requested, will return a fragment representing an object in
// the collection.
//
// ViewPager and its adapters use support library fragments, so we must use
// getSupportFragmentManager.
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getSupportFragmentManager());
// Set up action bar.
final ActionBar actionBar = getActionBar();
// Specify that the Home button should show an "Up" caret, indicating that touching the
// button will take the user one step up in the application's hierarchy.
actionBar.setDisplayHomeAsUpEnabled(true);
// Set up the ViewPager, attaching the adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// This is called when the Home (Up) button is pressed in the action bar.
// Create a simple intent that starts the hierarchical parent activity and
// use NavUtils in the Support Package to ensure proper handling of Up.
Intent upIntent = new Intent(this, MainActivity.class);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// This activity is not part of the application's task, so create a new task
// with a synthesized back stack.
TaskStackBuilder.from(this)
// If there are ancestor activities, they should be added here.
.addNextIntent(upIntent)
.startActivities();
finish();
} else {
// This activity is part of the application's task, so simply
// navigate up to the hierarchical parent activity.
NavUtils.navigateUpTo(this, upIntent);
}
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A {#link android.support.v4.app.FragmentStatePagerAdapter} that returns a fragment
* representing an object in the collection.
*/
public static class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1); // Our object is just an integer :-P
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// For this contrived example, we have a 100-object collection.
return 100;
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
*/
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "object";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
Integer.toString(args.getInt(ARG_OBJECT)));
return rootView;
}
}
}
I learned that having connected Activities is deprecated and just use nested fragments instead.
From Docu:
Nested Fragments - Fragments have its own life cycle like an activity.