Fragment inside ViewPager inside ViewGroup - android

Problem
As shown in the figure below, I have two tabs called "température" which are created in the same way (see mainFragment). In this two tabs, I have a viewpager to get previous graphics ( 05 august, 04 august,...).
The first tab works well but in the second, nothing appears. When debugging, I can see that the fragment is created in both cases. It's only on the second tab where the problem is. Even more, I can see the viewpager working when sliding to the left or right end.
I'm seeking since hours now and I don't understand where the problem is. Why the fragments don't appear ?
I'm using android.support.v13.app.FragmentStatePagerAdapter for the adapter.
Here is a short movie to show the problem :
https://www.dropbox.com/s/vf8qlrd75mdwijp/device-2017-08-06-214510.mp4?dl=0
Code
MainFragment
public class MainFragment extends Fragment implements BTListener {
// the different ID for the views.
private final static int ID_TEMPERATURE = 1;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.main,container,false);
final ViewGroup mainContainer = (ViewGroup) rootView.findViewById(R.id.main_container);
createTemperatureTab(mainContainer);
createTemperatureTab(mainContainer);
return rootView;
}
private void createTemperatureTab(ViewGroup mainContainer){
//inflate the view
ViewGroup view = (ViewGroup) LayoutInflater.from(getActivity()).inflate(R.layout.main_list,mainContainer,false);
((TextView)view.findViewById(R.id.title_main_list)).setText("Température");
((TextView)view.findViewById(R.id.information_main_list)).setText("°C");
final ExpandableLayout expandableLayout = (ExpandableLayout) view.findViewById(R.id.expandable_layout);
CustomPager viewPager = (CustomPager) view.findViewById(R.id.viewpager);
LinearGraphAdapter linearGraphAdapter = new LinearGraphAdapter(getChildFragmentManager());
viewPager.setAdapter(linearGraphAdapter);
viewPager.setCurrentItem(linearGraphAdapter.getCount());
expandableLayout.setExpanded(false);
expandableLayout.setDuration(500);
expandableLayout.setInterpolator(new DecelerateInterpolator());
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(expandableLayout.isExpanded()) {
expandableLayout.collapse();
}
else {
expandableLayout.expand();
}
}
});
mainContainer.addView(view);
}
}
main_list
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:src="#mipmap/ic_launcher" />
<TextView
android:id="#+id/title_main_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:textSize="20sp" />
<TextView
android:id="#+id/information_main_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="80dp"
android:textSize="20sp" />
</LinearLayout>
<net.cachapa.expandablelayout.ExpandableLayout
android:id="#+id/expandable_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.renaud.aquariumslinding.adapter.CustomPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.example.renaud.aquariumslinding.adapter.CustomPager>
</net.cachapa.expandablelayout.ExpandableLayout>
</LinearLayout>
LineGraphFragment
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.linear_graph_layout,container,false);
lineChart = (LineChart) rootView.findViewById(R.id.linear_graph);
initiateChart(lineChart); // not important for this case
drawChart(lineChart,dayOfYear); // not important for this case
return rootView;
}
linear_graph_layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/linear_graph_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:elevation="4dp"
android:textColor="#fff" />
<com.github.mikephil.charting.charts.LineChart
android:id="#+id/linear_graph"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
LinearGraphAdapter
public class LinearGraphAdapter extends FragmentStatePagerAdapter {
public static int MAXIMUM_COUNT_PAGER = 7;
private int mCurrentPosition = -1;
public LinearGraphAdapter(FragmentManager fragmentManager){
super(fragmentManager);
}
#Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
bundle.putInt(Constant.CUSTOM_PAGER_NUMBER,MAXIMUM_COUNT_PAGER-position);
Fragment fragment = new LinearGraphFragment();
fragment.setArguments(bundle);
return fragment;
}
#Override
public int getCount() {
return MAXIMUM_COUNT_PAGER;
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition) {
Fragment fragment = (Fragment) object;
CustomPager pager = (CustomPager) container;
if (fragment != null && fragment.getView() != null) {
mCurrentPosition = position;
pager.measureCurrentView(fragment.getView());
}
}
}
}

Ok, after a night of research and reading the API I figured it out. I don't understand everything but it seems the v13 and v4 library have a conflict.
To override it, firstly :
Make sure that you called getChildFragmentManager() instead of getFragmentManager()
Create a different ID for all the different viewpageryou have. Those IDs must have at least 4 digits. Of course, it is better to have those in R.String
Set your ID in every viewpager by calling setID()
If it doesn't work, please clean and rebuild your project.
And finally, the reward :
I hope that it will help.

Related

Image Swipe Using View Pager inside Fragment

I am trying to create a swiping images inside fragment. I had created tabbed activity using view pager and this is working fine. In one of the tab I am trying to create Image swipe.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.fragment_collection_fragment1, container, false);
ViewPager viewPager= (ViewPager)view.findViewById(R.id.collection1_viewPager);
ImageSwipeAdapter imageSwipeAdapter= new ImageSwipeAdapter(getActivity().getSupportFragmentManager());
viewPager.setAdapter(imageSwipeAdapter);
return view;
}
After deploying this the app stops working.
In some internet content it was mention to use
getChildFragmentManager()
but it was also not working. What is the issue with the code?
Adapter code for Image Swipe
public class ImageSwipeAdapter extends FragmentStatePagerAdapter {
public ImageSwipeAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment f= new ImageSwipe();
Bundle args= new Bundle();
args.putInt("count", position + 1);
f.setArguments(args);
return f;
}
#Override
public int getCount() {
return 3;
}
}
Fragment 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"
tools:context="com">
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="500dp"
android:id="#+id/collection1_viewPager">
</android.support.v4.view.ViewPager>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="160dp"
android:layout_marginTop="203dp"
android:text="TextView" />

Depth Pager Transformer just like SnapChat

I'm trying to implement ViewPager with DepthPageTransformer just like Snapchat application. In SnapChat application, there is a Camera screen which always comes in center of ViewPager and swiping from left or right brings other fragments on top of camera screen.
I've found code for DepthPageTransformer from this link. But the problem with this demo is that it brings all the next screen views from behind. Just like SnapChat I've a Camera screen in center and 2 screens coming on top from left and two screens coming on top from right on Camera screen.
So, how can I create a PageTransformer which brings fragments from left or right on the top of my center screen which is Camera?
I think you should provide 5 fragments in your FragmentPagerAdapter, the third (index=2) fragment will be fragment with camera view,
viewPager.setCurrentItem(2); //2 is index of camera fragment
Then your ViewPager.PageTransformer should look like this:
#Override
public void transformPage(View page, float position) {
int pageIndex = (int) page.getTag(); //im stroing pageIndex of fragment in its tag
if(pageIndex == 2) { //2 is index of camera fragment
float currentTranslation = - position * page.getWidth();
ViewCompat.setTranslationX(page, currentTranslation);
ViewCompat.setTranslationZ(page, -1);
return;
}
I am stroing pageIndex while fragment's view is created in its tag.
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
...
view.setTag(pageIndex);
return view;
}
Here is gif with results:
https://media.giphy.com/media/OIwmXdr3nukq4/giphy.gif
Fragment with food is the one you should replace with your camera fragment.
This is what they have done, if you don't get the concept shoot a comment.
Basically what they are doing is they have a MainActivity which is showing the camera and it is holding those three buttons in the bottom plus its holding viewpager that viewpager is holding three fragments
1.LeftFragment (Fragment on the left side).
2.CenterFragment (This fragment is transparent so when it comes in center the mainactivity content is visible which is camera).
3.RightFragment(Fragment on the right side).
Now Comes the coding part.
MainActivity.java.
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
#RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mViewPager.setAdapter(new PagerAdapter(getSupportFragmentManager()));
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Here calculate the amount by which the pages are scrolled and animate your buttons accordingly.
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
class PagerAdapter extends FragmentStatePagerAdapter {
public PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new LeftFragment();
case 1:
return new CenterFragment();
case 2:
return new RightFragment();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Here is your camera."
android:textAppearance="?android:attr/textAppearanceLarge"/>
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Button"/>
</RelativeLayout>
Then comes the fragments
LeftFragment.java
public class LeftFragment extends BaseController {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sheet2, container, false);
return rootView;
}
}
fragment_left.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFA726"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:fontFamily="sans-serif"
android:text="Left"
android:textColor="#fff"
android:textSize="30sp"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
RightFragment.java
public class RightFragment extends BaseController {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sheet1, container, false);
return rootView;
}
}
fragment_right.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFA726"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:fontFamily="sans-serif"
android:text="Right"
android:textColor="#fff"
android:textSize="30sp"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
I have left the animation part which I think you can achieve with little bit of calculation in viewpager OnPageChangeListener.
Happy Coding.

ViewPager shows views on top of each other

I am trying to implement a ViewPager, but currently it renders all the views on one screen, and when moving to the next it is empty it contains all the content. I have a feeling it has to do with the Fragment within Fragment or so, but I cannot figure it out.
In the screenshot below you can kind of see it:
This is (part) of the code. (ArticlePagerAdapter is just an implementation of the proto to look up that specific object type).
public abstract class PrototypePagerActivity<T extends GenericModel> extends BaseActivity {
PrototypePagerAdapter mAdapter;
ViewPager mPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_proto_pager);
long categoryId = -1;
int articlePos = 0;
Bundle extras = getIntent().getExtras();
if (extras != null) {
//if (extras.containsKey("articleId")) articleId = extras.getInt("articleId");
if (extras.containsKey("position")) articlePos = extras.getInt("position");
if (extras.containsKey("categoryId")) categoryId = extras.getLong("categoryId");
}
mAdapter = new ArticlePagerAdapter(categoryId,getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.protoPager);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(articlePos);
}
}
public abstract class PrototypePagerAdapter<T extends GenericModel> extends FragmentPagerAdapter {
#Override
public Fragment getItem(int position) {
try {
T object = getObjectForPosition(position);
ArticleFragment articleFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putLong("articleId", object.getId());
articleFragment.setArguments(args);
return articleFragment;
} catch (Exception e) {
Log.w(iDomsAndroidApp.TAG, "Problem getting the object instance for pages", e);
return null;
}
}
public abstract T getObjectForPosition(int position) throws Exception;
#Override
public int getCount() {
return requestObjectCount();
}
public abstract int requestObjectCount();
}
public class ArticleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_article, container, false);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.content_fragment, new PlaceholderFragment())
.commit();
}
ArticleHeaderFragment articleHeaderFragment = new ArticleHeaderFragment();
articleHeaderFragment.setArguments(getArguments());
getFragmentManager().beginTransaction().add(R.id.header_fragment, articleHeaderFragment).commit();
ArticleContentFragment articleContentFragment = ArticleContentFragment.newInstance();
articleContentFragment.setArguments(getArguments());
getFragmentManager().beginTransaction().add(R.id.content_fragment, articleContentFragment).commit();
return view;
}
}
activity_proto_pager.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/protoPager" />
</LinearLayout>
fragment_article.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/imageView"
android:src="#drawable/background"
android:scaleType="centerCrop"
android:contentDescription="#string/background_image"
android:alpha="0.6" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="vertical">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/audio_control_fragment" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/header_fragment" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/content_fragment" />
</LinearLayout>
</ScrollView>
</RelativeLayout>
fragment_article_header.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/list_background_overlay"
android:layout_centerInParent="true"
tools:context="org.idoms.iDomsAndroid.fragments.ArticleHeaderFragment">
<org.idoms.iDomsAndroid.views.ResizableImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxHeight="200dp"
android:id="#+id/article_imageView"
android:layout_gravity="center_horizontal"
android:scaleType="centerCrop" />
</LinearLayout>
You should replace fragment instead of add.
So, instead of .add(...) use .replace(....)
Update:
You are adding fragment at two more places. Do above step with articleHeaderFragment and articleContentFragment. You can add second part of code in else part (If it is according to your logic)
Update 2
You should revisit your logic as well. Like in the code, below, you are adding two fragment in R.id.content_fragment. Replace can help here, but your code will be redundant
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.content_fragment, new PlaceholderFragment())
.commit();
}
ArticleContentFragment articleContentFragment = ArticleContentFragment.newInstance();
articleContentFragment.setArguments(getArguments());
getFragmentManager().beginTransaction().add(R.id.content_fragment, articleContentFragment).commit();

Switching 2 fragments within one activity - Android

I'm trying to replace one fragment with another following a button click (onClick) event. I'm new to fragments so if I'm going about this the wrong way please let me know.
At run time a frame layout (container) is loaded. A fragment is then added to it dynamically. This works fine. If I add in the setOnClickListener I get a NullPointerException. Here's the Java:
public class WelcomeActivity extends ActionBarActivity {
FrameLayout container;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
//setContentView(R.layout.welcome_fragment);
container = (FrameLayout)findViewById(R.id.mainContainer);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.mainContainer) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
addWelcomeFragment();
}
//NPE at the below line
Button submitUser = (Button) findViewById(R.id.submitUser);
submitUser.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
addExpedFragment();
}
});
}
Through researching fragments I'm using static class within the WelcomeActivity class to load the fragments. They are here:
public static class WelcomeFragment extends Fragment {
public static Fragment newInstance(){
Fragment wFrag = new WelcomeFragment();
return wFrag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.welcome_fragment, null);
return v;
}
}
//-----------------------------------------------------------------------------------------------------//
public static class ExpedFragment extends Fragment {
public static Fragment secondInstance(){
Fragment eFrag = new ExpedFragment();
return eFrag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.exped_fragment, null);
return v;
}
}
And the methods to invoke these are also with WelcomeActivity here:
private void addWelcomeFragment(){
Fragment welcome = WelcomeFragment.newInstance();
FragmentTransaction fTrans = getSupportFragmentManager().beginTransaction();
fTrans.add(R.id.mainContainer, welcome);
fTrans.addToBackStack(null);
fTrans.commit();
}
private void addExpedFragment(){
Fragment exped = ExpedFragment.secondInstance();
getSupportFragmentManager().beginTransaction().replace(R.id.mainContainer, exped).commit();
}
I have a feeling that the problem is to do with trying to find the button view id "submitUser" from the first fragment. My xmls look like this.
The first empty FrameLayout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
The first fragment loaded in at runtime:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/welcome_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
tools:context=".WelcomeActivity" >
<TextView
android:id="#+id/welcome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/welcome1"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="#+id/userName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/welcome"
android:layout_alignRight="#+id/welcome"
android:layout_below="#+id/welcome"
android:layout_marginTop="32dp"
android:ems="10"
android:hint="#string/userHint"
android:inputType="textPersonName" >
<requestFocus />
</EditText>
<Button
android:id="#+id/submitUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/userName"
android:layout_alignRight="#+id/userName"
android:layout_below="#+id/userName"
android:layout_marginTop="16dp"
android:text="#string/Done" />
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
The second fragment to replace the first with the onClick event:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/exped_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
tools:context=".WelcomeActivity" >
<TextView
android:id="#+id/expedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/exped"
android:textAppearance="?android:attr/textAppearanceLarge">
</TextView>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
IF I forget loading the first fragment at runtime and setContentView(first fragment) there is no NullPointerException but the two fragments overlay each other when the button is pressed rather than replacing.
So my question is, how do I reference the active fragment to properly set the OnClickListener and avoid the NullPointerException?
Button submitUser = (Button) findViewById(R.id.submitUser);
gives the NPE
Problem:
Button submitUser = (Button) findViewById(R.id.submitUser);
The submitUser is located in your WelcomeFragment's layout not in your Activity's layout that is why it is null.
solution:
Instead of initializing it in your activity class you need to initialize it within your Welcome fragment view.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.welcome_fragment, null);
Button submitUser = (Button) v.findViewById(R.id.submitUser);
submitUser.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
addExpedFragment();
}
});
return v;
}
EDIT:
private void addExpedFragment(){
Fragment exped = ExpedFragment.secondInstance();
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainContainer, exped).commit();
}

AsyncTask is re-executing while switching between fragments

I have a MainActivity.class which extends from Activity . I created a tab like structure . on clicking any of the image . new fragment is displayed. My first fragment is Article. it has a AsyncTask associate with it.
when i go to another fragment and comeback to it .asyncTask call again. And the whole listView is recreated . I simply want to disable AsyncTask for calling again and save the previous state of the fragment.
I have addToBackStack(null); while adding fragments.
getFragmentManager().beginTransaction().replace(R.id.container, new Article()).addToBackStack(null).commit();
where Article is a fragment and container is the frameLayout in the mainActivity.xml
I want to show the fragment where i left off. Like we do in Activities by setting LaunchMode+"Single" or something . I am not clearing backStack.
I simply need to switch between Activities like we do in TabActivity. in TabActivity if we want to repeat the AsyncTask we have to specify it in onResume(). otherwise it will not called
Article Fragment
public class Article extends Fragment
{
ListView listView;
Activity context;
ArrayList<HashMap<String,String>> art_list;
ArticleAdapter adapter;
String url="http://tabletennisdaily.co.uk/webservices/view_articles.php";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View V = inflater.inflate(R.layout.article, container, false);
context = getActivity();
listView = (ListView) V.findViewById(R.id.art_listview);
new ArticleTask(getActivity(), url, listView).execute(url);
return V;
}
}
MainActivity
public class MainActivity extends Activity //implements FragmentDelegate,FragmentManager.OnBackStackChangedListener
{
public LinearLayout Tab1,Tab2,Tab3,Tab4;
public ImageView img1,img2,img3,img4;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.practicing);
init();
}
private void init()
{
Tab1 = (LinearLayout) findViewById(R.id.tab1);
Tab2 = (LinearLayout) findViewById(R.id.tab2);
Tab3 = (LinearLayout) findViewById(R.id.tab3);
Tab4 = (LinearLayout) findViewById(R.id.tab4);
img1 = (ImageView)findViewById(R.id.tab_img1);
img2 = (ImageView)findViewById(R.id.tab_img2);
img3 = (ImageView)findViewById(R.id.tab_img3);
img4 = (ImageView)findViewById(R.id.tab_img4);
getFragmentManager().beginTransaction().replace(R.id.container, new Article()).addToBackStack(null).commit();
}
public void selectFrag(View view) {
Fragment fr = null;
if (view == findViewById(R.id.tab1))
{
img1.setBackgroundResource(R.drawable.articles_on);
img2.setBackgroundResource(R.drawable.forum_off);
img3.setBackgroundResource(R.drawable.video_off);
img4.setBackgroundResource(R.drawable.profile_off);
fr = new Article();
}
else if(view == findViewById(R.id.tab2))
{
img1.setBackgroundResource(R.drawable.articles_off);
img2.setBackgroundResource(R.drawable.forum_on);
img3.setBackgroundResource(R.drawable.video_off);
img4.setBackgroundResource(R.drawable.profile_off);
fr = new Forum();
}
else if(view == findViewById(R.id.tab3))
{
img1.setBackgroundResource(R.drawable.articles_off);
img2.setBackgroundResource(R.drawable.forum_off);
img3.setBackgroundResource(R.drawable.video_on);
img4.setBackgroundResource(R.drawable.profile_off);
fr = new Medias();
}
else if(view == findViewById(R.id.tab4))
{
img1.setBackgroundResource(R.drawable.articles_off);
img2.setBackgroundResource(R.drawable.forum_off);
img3.setBackgroundResource(R.drawable.video_off);
img4.setBackgroundResource(R.drawable.profile_on);
fr = new Profile();
}
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.container, fr);
fragmentTransaction.addToBackStack(null);//MainActivity.TAG);//.addToBackStack(null);
fragmentTransaction.commit();
}
}
and practicing.xml is
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainlayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottom" />
<LinearLayout
android:id="#+id/bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:layout_alignParentBottom="true"
android:orientation="horizontal" >
<LinearLayout
android:id="#+id/tab1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="selectFrag"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/tab_img1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#drawable/articles_on"
android:padding="10dp"
android:scaleType="center" />
</LinearLayout>
<LinearLayout
android:id="#+id/tab2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="selectFrag"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/tab_img2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#drawable/forum_off"
android:padding="10dp"
android:scaleType="center" />
</LinearLayout>
<LinearLayout
android:id="#+id/tab3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="selectFrag"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/tab_img3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#drawable/video_off"
android:padding="10dp"
android:scaleType="fitXY" />
</LinearLayout>
<LinearLayout
android:id="#+id/tab4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="selectFrag"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/tab_img4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#drawable/profile_off"
android:padding="10dp"
android:scaleType="fitXY" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Try adding your fragment instead of replacing.
What addToBackStack() does is: it adds the fragment transaction to its stack, so it knows that when you press back, it should show your first fragment. So t does exactly that, and shows your first fragment again and the fragment's onCreatView() is called again. Here in your onCreateView, all initialization occurs and the AsyncTask is called. This is why it happens everytime you change between fragments.
The solution I implemented for this problem is:
1) Keep view of fragment as a class variable.
2) Perform all actions in onCreateView() only if the view is null.
So you should change:
public class Article extends Fragment
{
ListView listView;
Activity context;
ArrayList<HashMap<String,String>> art_list;
ArticleAdapter adapter;
String url="http://tabletennisdaily.co.uk/webservices/view_articles.php";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View V = inflater.inflate(R.layout.article, container, false);
context = getActivity();
listView = (ListView) V.findViewById(R.id.art_listview);
new ArticleTask(getActivity(), url, listView).execute(url);
return V;
}
}
to:
public class Article extends Fragment
{
ListView listView;
Activity context;
ArrayList<HashMap<String,String>> art_list;
ArticleAdapter adapter;
String url="http://tabletennisdaily.co.uk/webservices/view_articles.php";
View V; //SET THE FRAGMENTS VIEW AS A CLASS VARIABLE HERE
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{ //CHECK IF FRAGMENT IS INSTANTIATED BEFORE. IF IT IS NOT, CREATE NEW VIEW
if(V == null){
V = inflater.inflate(R.layout.article, container, false);
context = getActivity();
listView = (ListView) V.findViewById(R.id.art_listview);
new ArticleTask(getActivity(), url, listView).execute(url);
}
else{ //IF ALREADY INSTANTIATED USE SAME OLD V
((ViewGroup)V.getParent()).removeView(V);
}
return V;
}
}
Here, we move View V outside and make it a class variable. So if it is the first time the fragment is called, it is null and the initialization occurs, otherwise it goes to else black. Else block is required because onCreateView() adds whatever it returns as a child of the view's parent, so since V is already there, we remove it and onCreateView automatically adds it again.

Categories

Resources