Ok, so I'm trying to use Sherlock to display multiple tabs, each for one fragment.
I've got only 4classes : one for my main activity, two for my fragments, and one for the TabListener.
Everything should be ok (I've got quite the same program without Sherlcock, working on 4.0 devices), so I can't understand why i get that NullPointerException.
Here's part of the error
05-18 17:46:57.197: E/AndroidRuntime(9312): FATAL EXCEPTION: main
05-18 17:46:57.197: E/AndroidRuntime(9312): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.micky.testing/com.micky.testing.SherlockTestActivity}: java.lang.NullPointerException
...
05-18 17:46:57.197: E/AndroidRuntime(9312): Caused by: java.lang.NullPointerException
05-18 17:46:57.197: E/AndroidRuntime(9312): at com.micky.testing.MyTabListener.onTabSelected(MyTabListener.java:21)
...
05-18 17:46:57.197: E/AndroidRuntime(9312): at com.micky.testing.SherlockTestActivity.onCreate(SherlockTestActivity.java:39)
Here is one of my fragment :
HomeFragment
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.actionbarsherlock.app.SherlockFragment;
public class HomeFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.homefragment, container, false);
}
}
Here is my tabListener :
MyTabListener
public class MyTabListener implements TabListener {
public SherlockFragment fragment;
MyTabListener(SherlockFragment fr) {
Log.d("MYTAG", "Creating a fragmentListener w/ " + fr);
this.fragment = fr;
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
Log.d("TAG", "" + fragment);
ft.replace(R.id.fragment_container, fragment);
}
}
And my main activity :
SherlockTestActivity
public class SherlockTestActivity extends SherlockActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//We take the support actionbar
ActionBar ab = getSupportActionBar();
//We set to navigationmode with tabs
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//we create the tabs
ActionBar.Tab homeTab = ab.newTab().setText("Home");
ActionBar.Tab tagsTab = ab.newTab().setText("Tags");
//We create the fragments
SherlockFragment homeFragment = new HomeFragment();
SherlockFragment tagsFragment = new TagFragments();
//And we set the tabsListener;
homeTab.setTabListener(new MyTabListener(homeFragment));
tagsTab.setTabListener(new MyTabListener(tagsFragment));
Log.d("","" + homeTab);
ab.addTab(homeTab);
ab.addTab(tagsTab);
}
Ok, so the error seems to be thrown when I add the tab to my actionbar. And when I don't add the TabListener to the tab, there's no error.
The code ft.replace(R.id.fragment_container, fragment); (MyTabListener) seems to be the problem, but i can't manage to understand why. fragment isn't null (initialized when instanciating a new tabListener), and there's no reason the fragment_container is wrong.
So if anyone can manage to help me around here ! Thank you !
You should be extending SherlockFragmentActivity instead of SherlockActivity. Use a fragment activity when you are managing fragments.
Related
I have an application with multiple fragments.
My first fragment is HomeFragment where I am using viewpager and recycler view.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_home, container, false);
ButterKnife.bind(this, view);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(Constant.HOME_TITLE);
// view Pager
mPager = (ViewPager) view.findViewById(R.id.pager);
// recycler view
rv_transactions.setHasFixedSize(true);
LinearLayoutManager mLayoutmanager = new LinearLayoutManager(getContext());
rv_transactions.setLayoutManager(mLayoutmanager);
}
In HomeFragment's onStart I am doing network call using asyncTask. On compltion of asynctask I have a callback onTaskComplete() where I am setting my list and pager
public void onTaskComplete(JSONObject response){
// some jsonparsing logic, then
TransactionRecyclerViewAdapter adapter = new TransactionRecyclerViewAdapter(cardInfoAndTransactionArrayList.get(0).getTransactions());
Log.d("rv_adapter",""+cardInfoAndTransactionArrayList.get(0).getTransactions());
rv_transactions.setAdapter(adapter);
mPagerAdapter = new MultipleCardPagerAdapter(getChildFragmentManager(), cardInfoAndTransactionArrayList);
Log.d("ArrayList size",""+cardInfoAndTransactionArrayList.size());
Log.d("mPagerAdapter",""+mPagerAdapter);
Log.d("mPager",""+mPager);
mPager.setAdapter(mPagerAdapter);
mPager.addOnPageChangeListener(this);
}
Then there is one fragmentBy the name IgFragment from where I am coming back to HomeFragment
android.support.v4.app.FragmentManager fManager = getActivity().getSupportFragmentManager();
Boolean isPoped = fManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
HomeFragment homeFragment = HomeFragment.newInstance(mobileNumber, "");
FragmentTransaction transaction = fManager.beginTransaction();
transaction.replace(R.id.fragment_container, homeFragment);
transaction.commit();
The flow of app is like HomeFragment --> 1st Frag --> 2nd Frag -->IGFragment --> HomeFragment and I am adding 1 & 2 to addToBackStack(null) to have back button navigation but at IGFragment I am clearing the back stack because I don't want any back navigation behaviour when I am at homeFragment but clearing backstack makes viewPager throw nullpointer exception
logcat output (before exception thrown)
ArrayList size: 2
/mPagerAdapter: com.example.worldline.adapters.MultipleCardPagerAdapter#36efdd11
/mPager: android.support.v4.view.ViewPager{5a27e76 VFED.... ......ID 0,0-1080,486 #7f0f00f8 app:id/pager}
logcat Output (Exception thrown at mPager.setAdapter(mPagerAdapter);)
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
If I dont clear back stack everything works fine but HomeFragment shows multiple fragments one above other on press of back button (but no exception from viewpager) but if I clear backstack it throws null pointer even though arraylist have size 2(logact output printed just before setting adapter to viewpager)
MultipleCardPagerAdapter code
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import com.example.worldline.pojo.CardInfoAndTransactionsPojo;
import com.example.worldline.r_cug.MultipleCardViewPagerFragment;
import java.util.ArrayList;
/**
* Created by sunny.birman on 28-10-2016.
*/
public class MultipleCardPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<CardInfoAndTransactionsPojo> cardDetails;
private int cardListLength;
public MultipleCardPagerAdapter(FragmentManager fm, ArrayList<CardInfoAndTransactionsPojo> list) {
super(fm);
this.cardDetails= list;
cardListLength = list.size();
}
#Override
public Fragment getItem(int position) {
return MultipleCardViewPagerFragment.newInstance(cardDetails.get(position).getCardNumber(),cardDetails.get(position).getCardBalance(),position,cardListLength);
}
#Override
public int getCount() {
return cardDetails.size();
}
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
}
I created a class called SlidingFragment that extends from Fragment, and in my MainActivity I put these lines:
MainActivity.java :
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setUpView();
setUpFragment();
}
void setUpView(){
setContentView(R.layout.activity_main);
}
void setUpFragment(){
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
SlidingFragment fragment = new SlidingFragment();
transaction.replace(R.id.sample_content_fragment, fragment);
transaction.commit();
}
}
The problem is that the replace() method of the FragmentTransaction class can't recognize the second argument fragment which is a SlidingFragment object. I get this:
wrong second argument type found.'SlidingFragment' required 'android.support.v4.app.Fragment'.
replace(int,android.support.v4.app.Fragment)
to
replace(int,com.example.g514110.IhmSlidingTabs.SlidingFragment)
I understand the problem, but I don't know how to solve it.
Can someone please help.Thanks
Do that SlidingFragment extends
import android.support.v4.app.Fragment;
and not
android.app.Fragment
Make sure your SlidingFragment is extending android.support.v4.app.Fragment. Based on this compiler error, it currently is not.
Before I am also facing this issue , I did few changes . Now it's Workking Fine
New frgment page Eg : home_fragment
import android.support.v4.app.Fragment;
Main XML Design must contain any layout with your id eg :
android:id="#+id/fragment_container"
Main Java Class
import android.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
Click Event
home_fragment fragment = new home_fragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
This Code Workking Fine For Me
In my Android application I have created a simple Navigation Drawer which calls fragments when an item is clicked. From one of these fragments, I want to call a FragmentActivity (which will make scrollable tabs from within one of my fragments). Is this possible? Can someone please help me. A similar example to what I'm trying to achieve is in Play Music. It has a Navigation Drawer and upon selecting 'My Library' it creates a Fragment with scrollable tabs whilst still having the NavDrawer accessible from that page.
Regards,
import android.app.ActionBar;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import cgg.gov.in.apps.eoffice.source.R;
public class TestTabsinsideFragment extends Fragment
{
View rootView;
public TestTabsinsideFragment ()
{
// Empty constructor required for fragment subclasses
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
getActivity().getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Apply the layout for the fragment
rootView = inflater.inflate(R.layout.approve_leaves, container, false);
getActivity().setTitle("New tabbed layout inside Fragment :-) ");
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// show the given tab
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
// hide the given tab
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// probably ignore this event
}
};
// Add 3 tabs, specifying the tab's text and TabListener
for (int i1 = 0; i1 < 3; i1++) {
getActivity().getActionBar().addTab(
getActivity().getActionBar().newTab()
.setText("Tab " + (i1 + 1))
.setTabListener(tabListener));
}
return rootView;
}
Did this answer your question ??
Include this code in your Fragment and call it from onSelectItem() of Nav-Drawer
I am trying to build an app that will implement Action Bar tabs. One of the tabs should contain a MapFragment.
How can I implement an action bar with tabs, under one of which is a map Fragment?
Can you help me with how to proceed with this?
Here is what I have so far :
main class
package com.nfc.demo;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
public class NFCDemoActivity extends Activity {
Tab selectedTab = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getActionBar();
bar.setDisplayShowHomeEnabled(false);
bar.setDisplayShowTitleEnabled(false);
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setCustomView(R.layout.main);
ActionBar.Tab mapTab = bar.newTab().setText("Map");
ActionBar.Tab settingsTab = bar.newTab().setText("Settings");
ActionBar.Tab aboutTab = bar.newTab().setText("About");
MapFragment mapFragment = new MapFragment();
SettingsFragment settingsFragment = new SettingsFragment();
AboutFragment aboutFragment = new AboutFragment();
mapTab.setTabListener(new TabListener(mapFragment));
settingsTab.setTabListener(new TabListener(settingsFragment));
aboutTab.setTabListener(new TabListener(aboutFragment));
Tab selectedTab = (Tab) getLastNonConfigurationInstance();
if (selectedTab == null) {
bar.addTab(mapTab, false);
bar.addTab(settingsTab, false);
bar.addTab(aboutTab, true);
}
setContentView(R.layout.main);
}
public Object onRetainNonConfigurationInstance() {
return selectedTab;
}
protected boolean isRouteDisplayed() {
return false;
}
protected class TabListener implements ActionBar.TabListener {
private Fragment fragment;
public TabListener(Fragment fragment) {
this.fragment = fragment;
}
public void onTabSelected(Tab tab, FragmentTransaction fragmentTransaction) {
fragmentTransaction.replace(R.id.mainFragment, this.fragment, null);
selectedTab = tab;
}
public void onTabUnselected(Tab tab, FragmentTransaction fragmentTransaction) {
fragmentTransaction.remove(this.fragment);
}
public void onTabReselected(Tab tab, FragmentTransaction fragmentTransaction) {
//do nothing
}
}
}
The Fragment classes are all just returning an inflater with an .xml layout.
XML Layouts :
main.xml ( map should be on this XML file )
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
</LinearLayout>
settings.xml AND about.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="horizontal" >
<TextView
android:id="#+id/textView123"
android:text="asdfg"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
But adding the MapFragment thows a error:
Error inflating class fragment
error caused by java.lang.IllegalArgumentException:
Binary XML file line #2: Duplicate id 0x7f040005, tag null, or parent id 0x1020002 with another fragment for com.google.android.gms.maps.MapFragment 12-28 21:14:07.991: E/AndroidRuntime(26189): at android.app.Activity.onCreateView(Activity.java:4722)
I've been trying to figure out how to proceed for a couple of days but I am really confused.
Any help/tips would be greatly appreciated.
Also, what about getLastNonConfigurationInstance()? It is deprecated.
In the following solution, it is possible to add a GoogleMap to an Action Bar tab/dropdown. The key to doing this lies in correctly setting up your fragment to destroy the MapFragment when switching to another fragment in the Action Bar.
Create an Activity that implements the Action Bar functionality:
Create a project in Eclipse that uses Tabs for the main activity. If you don't do this, proceed to steps 2-5.
Create a class that extends Activity and implements ActionBar.OnNavigationListener.
Create a layout XML file that is a container for your tab fragments when you switch between them.
Implement/override the following method in your Activity class: public boolean onNavigationItemSelected(int position, long id).
In this method, switch between the position object to determine the selected tab and set the fragment to a new instance using the FragmentManager like this: getFragmentManager().beginTransaction().replace(R.id.container, fragment).commit().
Create a fragment that holds the map:
Create a class that extends Fragment to use as your tab's fragment. Read [1] to better understand the MapFragment.
Create a layout XML file that contains a fragment element (as seen in [1]).Use the XML in that page to create a layout XML file and use it in your fragment class.
Inflate that layout XML file in your fragment class by overriding onCreateView.
Your app should now display a map in the tab that uses your fragment class, however, switching to another tab and back to the map tab will result in a duplicate view ID. To overcome this, go on to the next step.
In your fragment class, override the following method to specifically destroy the underlying GoogleMap object so that it can be recreated when the map tab loads your fragment class again:
#Override
public void onDestroyView() {
super.onDestroyView();
MapFragment f = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
if (f != null)
getFragmentManager().beginTransaction().remove(f).commit();
}
Not sure if you already resolved it or not.
You have to add google play services as library project to make it work. First I tried to add the jar file, but that didn't work.
How to implement show and hide fragment inside fragment in Android? I have added two fragment inside activity. One fragment containing menu and one fragment contain sub menu. I have lot of button in menu fragment like home, idea, etc. If i click idea button. I have to show sub menu. If I again click idea button, I have to hide the sub menu. Can anybody provide example, or how to access one view fragment in another fragment?
this is my layout main
?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<fragment class="com.gcm.fragment.CommonFragment"
android:id="#+id/the_frag"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<fragment class="com.gcm.fragment.SubFragment"
android:id="#+id/the_frag1"
android:layout_marginTop="130dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
In My fragment
package com.gcm.fragment;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class CommonFragment extends Fragment implements OnClickListener {
TextView txtIhaveIdea=null;
boolean menuVisible=false;
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.collapsed_menu2, container, false);
txtIhaveIdea=(TextView)layout.findViewById(R.id.txtIhaveAnIdea);
txtIhaveIdea.setOnClickListener(this);
return layout;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!menuVisible)
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragOne = new SubFragment();
ft.show(fragOne);
}
else
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragOne = new SubFragment();
ft.hide(fragOne);
}
}
}
Thanks
You could try get framelayout or fragment by id and change its visibility
View frag = findViewById(R.id.my_fragment);
frag.setVisibility(View.VISIBLE);
Considering this question has over 2K .. an answer may still help new readers so here it goes:
You don't really want to have FragmentManager and FragmentTransactions happening inside fragments not to have Casts nor potential harmful references to your Activity(s)
So what I do and works just fine is set an interface to the Fragment and give a method, say needsHide():
public class MyFrag extends Fragment {
public interface MyFragInterface {
public void needsHide();
}
Then implement it on your Activity:
public class MainActivity extends FragmentActivity implements MyFrag.MyFragInterface {
public void needsHide() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//find the fragment by View or Tag
MyFrag myFrag = (MyFrag)fragmentManager.findFragmentByTag(SOME_TAG);
fragmentTransaction.hide(myFrag);
fragmentTransaction.commit();
//do more if you must
}}
The only part that requires thought is when to call needsHide(), this you might do in your Fragment's onViewCreated, since you are sure that it's not too early for your MainActivity to commit transactions. If you place it onCreate() it may not work depending on what you do with oter fragments:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Making sure Main activity implemented interface
try {
if (USE_A_CONDITION) {
((MyFragInterface)this.getActivity()).needsHide();
}
} catch (ClassCastException e) {
throw new ClassCastException("Calling activity must implement MyFragInterface");
}
super.onViewCreated(view, savedInstanceState);
}
Simply, create a public method in your "parent" activity. which hides the fragment.
Then from within the fragment in your click event get the "parent|' activity, cast it and then call the method you created.
((ParentActitity)getActivity()).hideFragment();
You need to use an Interface to communicate with your parent Activity.
Take a look on Vogella's tutorial, "3.4. Application communication with Fragments". Here is the link
method hide():Hides an existing fragment. This is only relevant for fragments whose views have been added to a container, as this will cause the view to be hidden.
your code :
#Override
public void onClick(View v) {
if(!menuVisible)
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragOne = new SubFragment();
ft.show(fragOne);
}
else
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
// it's wrong , you just hide the fragment that not added to FragmentTransaction
Fragment fragOne = new SubFragment();
ft.hide(fragOne);
}
}
Below code worked for me..
View frag = findViewById(R.id.fragment);
frag.setVisibility(View.GONE);//Or View.INVISBLE