how to add different content in swiping pages in android - java

I'm using a horizontal paging app but it's a fixed content .I want to have a different content in each section like text or images not 1,2,3 numbers.
I hope you can help me with this.
and this is my code
package com.example.android.horizontalpaging;
import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.Locale;
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
/**
* The {#link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. 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}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {#link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
/**
* Create the activity. Sets up an {#link android.app.ActionBar} with tabs, and then configures the
* {#link ViewPager} contained inside R.layout.activity_main.
*
* <p>A {#link SectionsPagerAdapter} will be instantiated to hold the different pages of
* fragments that are to be displayed. A
* {#link android.support.v4.view.ViewPager.SimpleOnPageChangeListener} will also be configured
* to receive callbacks when the user swipes between pages in the ViewPager.
*
* #param savedInstanceState
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the UI from res/layout/activity_main.xml
setContentView(R.layout.sample_main);
// Set up the action bar. The navigation mode is set to NAVIGATION_MODE_TABS, which will
// cause the ActionBar to render a set of tabs. Note that these tabs are *not* rendered
// by the ViewPager; additional logic is lower in this file to synchronize the ViewPager
// state with the tab state. (See mViewPager.setOnPageChangeListener() and onTabSelected().)
// BEGIN_INCLUDE (set_navigation_mode)
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// END_INCLUDE (set_navigation_mode)
// BEGIN_INCLUDE (setup_view_pager)
// Create the adapter that will return a fragment for each of the three primary sections
// of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// END_INCLUDE (setup_view_pager)
// When swiping between different sections, select the corresponding tab. We can also use
// ActionBar.Tab#select() to do this if we have a reference to the Tab.
// BEGIN_INCLUDE (page_change_listener)
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// END_INCLUDE (page_change_listener)
// BEGIN_INCLUDE (add_tabs)
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.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
// callback (listener) for when this tab is selected.
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
// END_INCLUDE (add_tabs)
}
/**
* Update {#link ViewPager} after a tab has been selected in the ActionBar.
*
* #param tab Tab that was selected.
* #param fragmentTransaction A {#link android.app.FragmentTransaction} for queuing fragment operations to
* execute once this method returns. This FragmentTransaction does
* not support being added to the back stack.
*/
// BEGIN_INCLUDE (on_tab_selected)
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, tell the ViewPager to switch to the corresponding page.
mViewPager.setCurrentItem(tab.getPosition());
}
// END_INCLUDE (on_tab_selected)
/**
* Unused. Required for {#link android.app.ActionBar.TabListener}.
*/
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
/**
* Unused. Required for {#link android.app.ActionBar.TabListener}.
*/
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
// BEGIN_INCLUDE (fragment_pager_adapter)
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages. This provides the data for the {#link ViewPager}.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
// END_INCLUDE (fragment_pager_adapter)
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
// BEGIN_INCLUDE (fragment_pager_adapter_getitem)
/**
* Get fragment corresponding to a specific position. This will be used to populate the
* contents of the {#link ViewPager}.
*
* #param position Position to fetch fragment for.
* #return Fragment for specified position.
*/
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
Bundle args = new Bundle();
switch(position){
case 0:
fragment = new DummySectionFragment();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
break;
case 1:
fragment = new DummySectionFragment();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
break;
case 2:
fragment = new DummySectionFragment();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
break;
case 3:
fragment = new DummySectionFragment();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
break;
}
return fragment;
}
// END_INCLUDE (fragment_pager_adapter_getitem)
// BEGIN_INCLUDE (fragment_pager_adapter_getcount)
/**
* Get number of pages the {#link ViewPager} should render.
*
* #return Number of fragments to be rendered as pages.
*/
#Override
public int getCount() {
// Show 3 total pages.
return 4;
}
// END_INCLUDE (fragment_pager_adapter_getcount)
// BEGIN_INCLUDE (fragment_pager_adapter_getpagetitle)
/**
* Get title for each of the pages. This will be displayed on each of the tabs.
*
* #param position Page to fetch title for.
* #return Title for specified page.
*/
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
case 3:
return getString(R.string.title_section4).toUpperCase(l);
}
return null;
}
// END_INCLUDE (fragment_pager_adapter_getpagetitle)
}
/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
* This would be replaced with your application's content.
*/
public static class DummySectionFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_label";
public DummySectionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy, container, false);
TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
return rootView;
}
}
}

You must have 3 different classes extending fragment, instead of this DummySectionFragment...
in the method getItem of SectionsPagerAdapter, compare the position, and instantiate one or other fragment class...
The fragment class will have the content you want.
I don't speak English, but I hope I have helped you.
public class StudentsFragment extends Fragment {
//whatever the fragment will do here
}
public class TeachersFragment extends Fragment {
//whatever the fragment will do here
}
public class ClassesFragment extends Fragment {
//whatever the fragment will do here
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new StudenstFragment();
case 1:
return new TeachersFragment();
case 2:
return new ClassesFragment();
}
}
}

i don't really get what you are trying to do, but i get the main idea XD
why not to use a intent to call the same activity but send a varible which divide the code in diferent actions for example:
first the variable which controls the activity are going to do
String num ="";
then the button code, depends on how many you want
Button.setOnClickListener(new Button onclickListener(){
public void onClick(){
//get a default variable in this case String num
Intent intent = new Intent(MainActivity.this, MainActivity.class); num="cero"; intent.putExtra("po", num);
CodigoPeticion=2; startActivityForResult (intent,CodigoPeticion); finish(); break;
}
}
});
this one to get the String num:
Bundle extras = getIntent().getExtras();
if (extras!= null) {
num =extras.getString("po");
}
and at last but not least this one to do someting depending the String:
if (num.matches("cero")){
//do something, enable more buttons, disable radiobuttons, etc
}else if(num.matches("one")){//this string is from another button
//do something else in the same activity, as you spected enable radiobuttons, show a image, etc
}else{
//some textview with a specific title
TextView.setText("Something's Wrong");
}
hope that helps you, see ya!

Related

Static fragment prevents me from accessing my data object

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

How to access button in next fragment after swipe?

As you can see in this photo, if I click the 2 button in Title 1, the Fragment in FrameLayout appears. However, if I swipe to Title 2, the two buttons are not working.
Here is the code:
package com.flashcards;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {#link Fragment} subclass.
* Use the {#link BaseFlashCardsFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class BaseFlashCardsFragment extends Fragment implements View.OnClickListener {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_POSITION = "position";
// TODO: Rename and change types of parameters
private int position;
private String mParam2;
public BaseFlashCardsFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param position Parameter 1.
* #return A new instance of fragment BaseFlashCardsFragment.
*/
// TODO: Rename and change types and number of parameters
public static BaseFlashCardsFragment newInstance(int position) {
BaseFlashCardsFragment fragment = new BaseFlashCardsFragment();
Bundle args = new Bundle();
args.putInt(ARG_POSITION, position);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
position = getArguments().getInt(ARG_POSITION, 0);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = null;
int layoutId;
switch (position) {
case 0: layoutId = R.layout.limits_flashcardsfragment1; break;
case 1: layoutId = R.layout.limits_flashcardsfragment2; break;
default: layoutId = R.layout.limits_flashcardsfragment3; break;
}
rootView = inflater.inflate(layoutId, container, false);
rootView.findViewById(R.id.buttonterm).setOnClickListener(this);
rootView.findViewById(R.id.buttondefinition).setOnClickListener(this);
switchPage(new limits_fragmentpageA());
switchPage(new limits_fragmentpageB());
return rootView;
}
#Override
public void onClick(View view) {
int viewId = view.getId();
if (viewId == R.id.buttonterm)
switchPage(new limits_fragmentpageA());
else if (viewId == R.id.buttondefinition)
switchPage(new limits_fragmentpageAA());
else if (viewId == R.id.buttonterm)
switchPage(new limits_fragmentpageB());
else if (viewId == R.id.buttondefinition)
switchPage(new limits_fragmentpageBB());
}
private void switchPage (Fragment fragment){
android.support.v4.app.FragmentManager manager = getFragmentManager();
manager.beginTransaction()
.replace(R.id.activity_main_fragmentcontainer, fragment)
.commit();
}
}
You can also download the project to get a clear view.
As I can see you need to have ALL elements (buttons, viewpager, title etc) in your activity, not in fragment, because its are shared among all the fragments, so you do not need to recreate them in each fragment.
To change title (and lower hint), you need to add OnPageChangeListener to viewpager adapter.
To switch fragment between term/definition you need to pass the event directly in OnClickListener of those buttons, like "(BaseCardFragment)adapter.instantiateItem(viewpager,viewpager.getCurrentItem).flipToTerm() or flipToDefinition()"
I think the problem is that if you are in fragment you should you getChildFragmentManager() instead of getFragmentManager()
Probably you should just rewrite switchPage() like this
private void switchPage (Fragment fragment){
android.support.v4.app.FragmentManager manager = getChildFragmentManager();
manager.beginTransaction()
.replace(R.id.activity_main_fragmentcontainer, fragment)
.commit();
}

Unexpected top-level exception

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.

Using tabs in Android application

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

Android - Having Connected Activities Under One Tab Section

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.

Categories