I am building an Android app that uses the Helpshift API. It was all working, but I am currently trying to move everything into a TabLayout, using Fragments and an ActionBar. I made a mini app to figure out functionality of the fragments without messing everything else up. I have a home screen where you click a button and it starts the activity containing the TabLayout with the Fragments. I cannot figure out how to make the embeddable support fragments show up in the TabLayout. I'm pretty new to Android, so sorry if my code is not the best. Right now the placeholder is not being replaced in the fragment transaction, and I can't figure out why. I would greatly appreciate any advice! Thank you :) Let me know if I can provide anything else
Here is my main activity class (Helpshift info has been redacted for privacy reasons, hopefully my issue can still be fixed)
public class MainActivity extends AppCompatActivity {
Context mContext;
public ConstraintLayout layout;
Activity goToFragment;
public Button start;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_screen);
mContext = getApplicationContext();
goToFragment = MainActivity.this;
start = (Button) findViewById(R.id.button);
start.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick (View view) {
launchFragments();
}
});
//HELPSHIFT SET UP
Core.init(All.getInstance());
InstallConfig installConfig = new InstallConfig.Builder()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE)
.setEnableInAppNotification(true)
.build();
try {
Core.install(getApplication(),
"****APIKEY*****",
"****DOMAIN*****",
"****APPID******", installConfig);
} catch (InstallException e) {
android.util.Log.e("Helpshift", "install call : ", e);
}
}
private void launchFragments() {
Intent intent1 = new Intent(mContext, HomeTab.class);
intent1.putExtra("fragmentNumber", 0);
startActivity(intent1);
}
}
Here is my ViewPager Adapter class:
public class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager){
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Here is my fragment activity class:
public class HomeTab extends AppCompatActivity {
// ImageButton FindCareButton;
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
public Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
Intent intent1 = getIntent();
int var = intent1.getIntExtra("fragmentNumber", 0);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
viewPager.setCurrentItem(var);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
if (findViewById(R.id.placeholder) != null) {
if (savedInstanceState != null) {
return;
}
Fragment faqFragment = new Fragment();
faqFragment = Support.getFAQsFragment(HomeTab.this);
getSupportFragmentManager().beginTransaction().add(R.id.placeholder, faqFragment).commit();
}
}
private void setupViewPager(ViewPager viewPager){
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new FAQTab(), "FAQ");
viewPager.setAdapter(adapter);
}
}
Here is my FAQTab class:
public class FAQTab extends Fragment {
public FAQTab(){
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.faq_tab, container, false);
}
}
For layouts, my faq_tab layout is an empty FrameLayout with id "placeholder"
My home_screen layout is a ConstraintLayout with a button (id "button")
And here is my activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.sasha.fragment_tester.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/BarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
Related
For some reason, when I click on the Toolbar(toolbar) and Float button(button) in my app, the OnClickListener () method crashes the snippet and app
Although the ImageButton(OnOff) handler runs and does not crash the fragment
Fragment
public class ZnonkiFragment extends Fragment {
private SharedPreferences settings;
private ImageButton OnOff;
private ViewPager viewPager;
private DrawerLayout drawerLayout;
private MainActivity.PagerAdapter pagerAdapter;
private FloatingActionButton button;
final Context context = getActivity();
private androidx.appcompat.widget.Toolbar toolbar;
private TabLayout tabLayout;
private String ZvonOne, ZvonTwo;
private List<Fragment> list = new ArrayList<>();
private String url;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_znonki, container,
toolbar = view.findViewById(R.id.toolbar);
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.menu));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context,"lel",Toast.LENGTH_LONG).show();
}
});
//...
addListenerOnButton(view);
return view;
}
public boolean checkString(String string) {
try {
Integer.parseInt(string);
} catch (Exception e) {
return false;
}
return true;
}
public void addListenerOnButton (final View viewOne){
OnOff = viewOne.findViewById(R.id.onOff);
button = viewOne.findViewById(R.id.floatingActionButton);
OnOff.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//...
});
button.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(final View view) {
//...
});
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//...
});
}
}
XML
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ZnonkiFragment">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:title="Звонки"
app:titleTextColor="#FFFFFF" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:clickable="true"
android:focusable="true"
app:backgroundTint="#color/colorAccent"
app:backgroundTintMode="src_atop"
app:srcCompat="#drawable/kek" />
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize"
android:background="#color/colorPrimary"
android:isScrollContainer="true"
app:tabIndicatorColor="#android:color/white"
app:tabIndicatorHeight="6dp"
app:tabMode="scrollable"
app:tabSelectedTextColor="#android:color/white"
app:tabTextColor="#E6E6FA">
</com.google.android.material.tabs.TabLayout>
<ImageButton
android:layout_margin="16dp"
android:id="#+id/onOff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="#null"
app:srcCompat="#drawable/on" />
<androidx.viewpager.widget.ViewPager
android:id="#+id/rager"
android:layout_width="match_parent"
android:layout_height="557dp"
android:layout_marginTop="105dp"
/>
</FrameLayout>
Although this code worked in the main activiti
I don't know why but there are no errors in debug mode
What Kundan has suggested is correct but the fix is much easier.
You don't need this:
final Context context = getActivity();
If you need to gain access to the context in a Fragment you can call requireContext() if you need access to the Activity you can call requireActivity()
So your toast message can become:
Toast.makeText(requireContext(),"lel",Toast.LENGTH_LONG).show();
I think main cause of this issue is
final Context context = getActivity();
which is used in
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context,"lel",Toast.LENGTH_LONG).show();
}
});
please note the getActivity() method returns the current activity with which this fragment is attached. and you are calling while the fragment object is creating before it is attached to activity.
you can change the above code to :
Context context;
and override the method as
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
Hope this answers your question.
The solution is simple
In your fragment class file, dont create custom function for calling click events rather you can use the android's defaul method by simply implementing them in your class file and then override it. Thats makes the code more simpler and reusable in future.
public class ZnonkiFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
private SharedPreferences settings;
private ImageButton OnOff;
private ViewPager viewPager;
private DrawerLayout drawerLayout;
private FloatingActionButton button;
final Context context = getActivity();
private TabLayout tabLayout;
private String ZvonOne, ZvonTwo;
private List<Fragment> list = new ArrayList<>();
private String url;
private Toolbar mToolbar;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_znonki, container, false);
mToolbar = view.findViewById(R.id.toolbar);
mToolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_launcher_background));
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "lel", Toast.LENGTH_LONG).show();
}
});
//...
OnOff = view.findViewById(R.id.onOff);
OnOff.setOnClickListener(this);
OnOff.setOnLongClickListener(this);
button = view.findViewById(R.id.floatingActionButton);
return view;
}
public boolean checkString(String string) {
try {
Integer.parseInt(string);
} catch (Exception e) {
return false;
}
return true;
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.onOff:
//call your onclick function here...
break;
case R.id.floatingActionButton:
//call your onclick function here...
break;
}
}
#Override
public boolean onLongClick(View view) {
switch (view.getId()) {
case R.id.floatingActionButton:
//call your long click function here...
break;
}
return false;
}
}
I have left comments on particular Loc where you can add your code and check it. And the toolbar was crashing due to improper importing of the libraries. If you havent used the androidx library into your gradle file then you can go with simple toolbar which is of "import android.support.v7.widget.Toolbar". This will surely stop your onclick crash on toolbar.
If there is any issue, just let me know. Thank you.
I have a Fragment that allows the user to change their username that will be displayed in a TextView inside a Navigation Drawer. The Fragment, 'SettingsFragment' is inflated in the MainActivity.
SettingsFragment has an EditText where the user enters their username and a button to apply changes. The Navigation Drawer was created in the MainActivity, so I setup SharedPreferences to send the username over to MainActivity. I then proceeded to change the TextView in the Navigation Drawer with .setText(username), however nothing happens. But when I relaunch the app, the Navigation Drawer's TextView changes to the actual username that the user entered in the EditText.
SettingsFragment.java:
public class SettingsFragment extends Fragment {
public SettingsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_settings, container, false);
final TextInputEditText teiUserName = view.findViewById(R.id.teiUserName);
final TextView tvEditTextSub = view.findViewById(R.id.tvEditTextSubstitute);
Button btnApplyChanges = view.findViewById(R.id.btnApplyChanges);
btnApplyChanges.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String user_name = String.valueOf(teiUserName.getText());
tvEditTextSub.setText(user_name);
SharedPreferences.Editor editor = getActivity().getSharedPreferences("myPrefs", MODE_PRIVATE).edit();
editor.putString("name", user_name);
editor.apply();
}
});
return view;
}}
SettingsFragment XML:
<FrameLayout 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:padding="10dp"
tools:context="com.miguelpeachey.marketplacesimulator.Fragments.SettingsFragment">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputEditText
android:id="#+id/teiUserName"
android:layout_width="248dp"
android:layout_height="wrap_content"
android:layout_above="#+id/btnApplyChanges"
android:layout_marginBottom="28dp"
android:text="User"
android:textColorHint="#000" />
<Button
android:id="#+id/btnApplyChanges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="28dp"
android:background="#33993f"
android:padding="12dp"
android:text="Apply Changes"
android:textColor="#FFF" />
</RelativeLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
Fragment fragment;
SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
View headerView = navigationView.getHeaderView(0);
final TextView tvDrawerUsername = headerView.findViewById(R.id.tvDrawerUsername);
setSupportActionBar(toolbar);
sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE);
final String usernameID = sharedPreferences.getString("name", "User");
if (drawer.isDrawerOpen(GravityCompat.START)) {
tvDrawerUsername.setText(usernameID);
}}
There is more code in MainActivity.java but there's no need in including it.
In MainActivity.java, I also tried:
if (drawer.isDrawerOpen(GravityCompat.START)) {
tvDrawerUsername.setText(usernameID);
}
But it didn't even change the Navigation Drawer's TextView (tvDrawerUsername) after relaunching the app.
In conclusion, the app won't update tvDrawerUsername straight after the button click, but only after I relaunch the app.
Try This one:
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
Fragment fragment;
SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE);Toolbar toolbar = findViewById(R.id.toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
View headerView = navigationView.getHeaderView(0);
final TextView tvDrawerUsername = headerView.findViewById(R.id.tvDrawerUsername);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, null, "navigation_drawer_open", "navigation_drawer_close") {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
// Do whatever you want here
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
final String usernameID = sharedPreferences.getString("name", "User");
tvDrawerUsername.setText(usernameID);
}
};
drawer.addDrawerListener(toggle);
toggle.syncState();
setSupportActionBar(toolbar);
}
Try defining an TextView attribute on your SettingsFragment class definition :
public class SettingsFragment extends Fragment {
TextView tv;
public SettingsFragment() {
// Required empty public constructor
}
Define an setter for this attribute on the same class :
public void setTextView(TextView tv){
this.tv = tv
}
And from your activity, after initializing your fragment and your textView , pass the textView via the setter you just created :
fragment = new SettingsFragment();
fragment.setTextView(tvDrawerUsername);
Finally add textView.setText(user_name); iniside you onlick() method :
btnApplyChanges.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String user_name = String.valueOf(teiUserName.getText());
tvEditTextSub.setText(user_name);
SharedPreferences.Editor editor = getActivity().getSharedPreferences("myPrefs", MODE_PRIVATE).edit();
editor.putString("name", user_name);
editor.apply();
textView.setText(user_name);
}
});
Hope this helps
I have an application which has one main activity which in turn hosts two tabs. Each tab is a fragment. The first tab has an editText and a Button and on button press the text entered by the user must be displayed on the second tab fragment which hosts only one textView. I am using a listener to pass the data but for some reason the app crashes when i press the submit button. Any help would be appreciated. Here is my code:
MainActivity.java
public class MainActivity extends AppCompatActivity implements OnEditTextListener {
Toolbar toolbar;
ViewPager pager;
ViewPagerAdapter adapter;
SlidingTabLayout tabs;
CharSequence Titles[] = {"Home", "Events"};
int Numboftabs = 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Creating The Toolbar and setting it as the Toolbar for the activity
toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
// Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs);
// Assigning ViewPager View and setting the adapter
pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
// Assiging the Sliding Tab Layout View
tabs = (SlidingTabLayout) findViewById(R.id.tabs);
tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width
// Setting Custom Color for the Scroll bar indicator of the Tab View
tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
return getResources().getColor(R.color.ColorPrimary);
}
});
// Setting the ViewPager For the SlidingTabsLayout
tabs.setViewPager(pager);
}
#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_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void OnEditText(String data) {
Tab2 newFragment = (Tab2)adapter.getItem(1);
newFragment.updateDisplay(data);
}
}
Tab1.java
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
public class Tab1 extends Fragment
{
public interface OnEditTextListener {
public void OnEditText(String data);
}
OnEditTextListener editTextListener = null;
EditText edtText;
Button btnSubmit;
String val;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
editTextListener = (OnEditTextListener) activity;
} catch (ClassCastException ex) {
ex.printStackTrace();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.first_fragment, container, false);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
edtText = (EditText)getActivity().findViewById(R.id.edtText);
btnSubmit = (Button)getActivity().findViewById(R.id.btnSubmit);
btnSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
val = edtText.getText().toString();
editTextListener.OnEditText(val);
}
});
}
}
Tab2.java
public class Tab2 extends Fragment {
public static final String TAG = "DATA";
public static final String SAVE = "NBHJB";
String newdata = "";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null)
savedInstanceState.getInt(SAVE);
return inflater.inflate(R.layout.second_fragment, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
savedInstanceState.getString(SAVE);
}
}
public void updateDisplay(String data) {
newdata = data;
TextView randomData = (TextView) getActivity().findViewById(R.id.txtView1);
randomData.setText(newdata);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVE, newdata);
}
MainActivity.xml
<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="vertical"
tools:context=".MainActivity">
<include
android:id="#+id/tool_bar"
layout="#layout/tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_height="2dip"
android:background="#color/tabsScrollColor"
android:layout_width="wrap_content" />
<com.example.regi.tabsprove.SlidingTabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/prove"
android:elevation="2dp" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"></android.support.v4.view.ViewPager>
</LinearLayout>
second_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="#+id/txtView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="10dp"
android:text="Default Text"
android:textSize="20dp" />
</LinearLayout>
This is the error that I get
java.lang.NullPointerException
at com.example.regi.tabsprove.Tab2.updateDisplay(Tab2.java:36)
at com.example.regi.tabsprove.MainActivity.OnEditText(MainActivity.java:79)
at com.example.regi.tabsprove.Tab1$1.onClick(Tab1.java:51)
at android.view.View.performClick(View.java:4198)
at android.view.View$PerformClick.run(View.java:17158)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4918)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
at dalvik.system.NativeStart.main(Native Method)
I'm pretty sure that the line Tab2 newFragment = (Tab2)adapter.getItem(1); is creating a new instance of Tab2 instead of giving you the Fragment that you need. You should find a better way to get the instance of the Fragment that has been built to you by the ViewPager; I'm sure that this post can help you.
I found your design a bit complicated than regular data passing. From the logs, the issue is the program unable to find txtView1 in second fragment. It is always a good practice to use bundle for passing data.
I hope the following changes should fix your problem, but that's not the best way to do it.
Declare your TextView next to newData
public static final String TAG = "DATA";
public static final String SAVE = "NBHJB";
String newdata = "";
TextView randomData;
Initialize it in onCreateView()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null)
savedInstanceState.getInt(SAVE);
View rootView = inflater.inflate(R.layout.second_fragment, container, false);
randomData = (TextView) rootView.findViewById(R.id.txtView1);
return rootView;
}
Change the updateDisplay function
public void updateDisplay(String data) {
newdata = data;
randomData.setText(newdata);
}
Make sure you dont have any other items with same id as txtView1.
Here is the solution to everyone who might be facing the same issue:
public static String makeFragmentName(int containerViewId, long id) {
return "android:switcher:" + containerViewId + ":" + id;
}
public #Nullable
Fragment getFragmentForPosition(int position)
{
String tag = makeFragmentName(pager.getId(), position);
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
return fragment;
}
#Override
public void OnEditText(String data) {
Tab2 tab2 = (Tab2)getFragmentForPosition(1);
tab2.updateDisplay(data);
}
This code goes to MainActivity.java
So I'm new to android app writing, and I am trying to work on a practice app that I can hopefully turn into something later. I had 3 tabs in the actionbar that ran fine before I decided to try to add webview to one of them. Now it crashes with an IllegalStateException. And since I don't know too much about android at the moment, I can't seem to figure out what is wrong.
The main activity:
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
private String[] tabs = { "Web", "Facebook", "Twitter" };
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs)
{
actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
#Override
public void onPageSelected(int position)
{
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2)
{
}
#Override
public void onPageScrollStateChanged(int arg0)
{
}
});
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft)
{
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
// on tab selected
// show respected fragment view
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
}
The WebFragment with the webview:
public class WebFragment extends Fragment
{
private String url = getString(R.string.website);
//#Override
//public void onActivityCreated(Bundle savedInstanceState)
//{
//super.onActivityCreated(savedInstanceState);
//}
#SuppressLint("SetJavaScriptEnabled")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.web_fragment, container, false);
WebView tolerableWebView = (WebView) getView().findViewById(R.id.webview);
tolerableWebView.getSettings().setJavaScriptEnabled(true);
tolerableWebView.loadUrl(url);
return rootView;
}
}
the TabsPagerAdapter:
public class TabsPagerAdapter extends FragmentPagerAdapter
{
public TabsPagerAdapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int index)
{
switch (index) {
case 0:
// Top Rated fragment activity
return new WebFragment();
case 1:
// Games fragment activity
return new FacebookFragment();
case 2:
// Movies fragment activity
return new TwitterFragment();
}
return null;
}
#Override
public int getCount()
{
// get item count - equal to number of tabs
return 3;
}
}
The webfragment xml
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
</WebView>
The main activity xml:
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Any help would be great! Thanks
Generally you get that error when you try to perform work after the Fragment is no longer attached to the Activity. In the callback that triggers the IllegalStateException add a check for isAdded: http://developer.android.com/reference/android/app/Fragment.html#isAdded()
if(!isAdded()) {
return;
}
I have a tabbed view activity with 3 tabs and one fragment in each tab. Those fragments are managed by a FragmentPageAdapter linked to a viewpager.
Everything works fine until I try to have a 4th fragment (ServiceSpecifNotListFragment) that would be a nested fragment of one of the fragments (ServicesListFragment) managed by the FragmentPageAdapter.
When I try to replace the ServicesListFragment by the ServiceSpecifNotListFragment. I manage to replace only the list element from ServicesListFragment by the ServiceSpecifNotListFragment, the other view controller (a button) from ServicesListFragment remains....
I have been wondering if the problem lies in the fact that the method I use to replace the fragment by its subfragment is transaction.replace(R.id.service_list_fragment, newFragment).commit(); and service_list_fragment is the id of the listfragment main linear layout which contains the listview defined with the id: #id/android:list
The closest Q&A I found to this was this one but as far as I understood I am using the fragment container id correctly.
Here is the code and layout:
Layout of ServicesListFragment (the parent of the nested fragment)
<?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:id="#+id/service_list_fragment">
<Button
android:id="#+id/addServiceButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="AddService" />
<ListView android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<TextView android:id="#id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="No data"/>
</LinearLayout>
Layout of ServiceSpecifNotListFragment(the fragment to be nested)
<?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:id="#+id/service_notif_list_fragment" >
<ListView android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<TextView android:id="#id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="No data"/>
</LinearLayout>
Main activity xml layout (it is basically a reference to the pager):
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
Source code of ServiceListFragment, the call for the nesting of fragments is in the onListItemClick :
public class ServicesListFragment extends ListFragment {
private final String TAG = "ServicesListFragment";
Button addButton = null;
ServiceNotifRowAdapter adapter;
ArrayList<NotifService> list = new ArrayList<NotifService>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Activity parent = getActivity();
// some ommited code for populating adapter with list of stored subscriptions
adapter = new ServiceNotifRowAdapter(getActivity().getApplicationContext(),list);
setListAdapter(adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.servicelist_fragment, container, false);
addButton = (Button) rootView.findViewById(R.id.addServiceButton);
MainActivity m = (MainActivity) getActivity();
addButton.setOnClickListener(m);
return rootView;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
NotifService item = (NotifService) getListAdapter().getItem(position);
Log.d(TAG, "selected service " + item.getServiceURI());
Fragment newFragment = new ServiceSpecifNotListFragment();
Bundle bundle = new Bundle();
bundle.putString("service", item.getServiceURI());
newFragment.setArguments(bundle);
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.addToBackStack(null);
transaction.replace(R.id.service_list_fragment, newFragment).commit();
}
Main activity java code
public class MainActivity extends FragmentActivity implements TabListener, AddServiceDialogFragmentListener
, OnClickListener{
private final String TAG = "MQTT main activity";
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, StatusListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ServicesListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ConfigFragment.class.getName()));
mAdapter = new TabsPagerAdapter(getSupportFragmentManager(),fragments);
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : MqttApplication.tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
// lock the screen in portrait mode
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
Tabs page adapter
public class TabsPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
private FragmentManager fm;
private final String TAG = "TabsPagerAdapter";
public TabsPagerAdapter(FragmentManager fm,List<Fragment> fragments) {
super(fm);
this.fm = fm;
this.fragments = fragments;
}
#Override
public Fragment getItem(int index) {
return this.fragments.get(index);
}
#Override
public int getCount() {
return this.fragments.size();
}
// 0 - Status, 1 Service, 2 Config (due to the order in which they have been added)
public Fragment findFragmentByPosition(int position) {
return fm.findFragmentByTag(
"android:switcher:" + R.id.pager + ":"
+ this.getItemId(position));
}
}
Just an alternate solution : implemented callbacks in your code and asked your view pager to load SpecificListNotFragment when item clicked in ServiceListFragment. Have a look and try it!
public class ServicesListFragment extends ListFragment {
private final String TAG = "ServicesListFragment";
Button addButton = null;
ServiceNotifRowAdapter adapter;
ArrayList<NotifService> list = new ArrayList<NotifService>();
private onListItemClickCallbackListener mCallback;
public interface onListItemClickCallbackListener {
public void replaceFragmentToServiveListNot();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Activity parent = getActivity();
mCallback = parent; // remember to imlement onListItemClickCallbackListener in activity else it will give error
// some ommited code for populating adapter with list of stored subscriptions
adapter = new ServiceNotifRowAdapter(getActivity().getApplicationContext(),list);
setListAdapter(adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.servicelist_fragment, container, false);
addButton = (Button) rootView.findViewById(R.id.addServiceButton);
MainActivity m = (MainActivity) getActivity();
addButton.setOnClickListener(m);
return rootView;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
NotifService item = (NotifService) getListAdapter().getItem(position);
Log.d(TAG, "selected service " + item.getServiceURI());
mCallback.replaceFragmentToServiveListNot();
}
}
public class MainActivity extends FragmentActivity implements TabListener, AddServiceDialogFragmentListener
, OnClickListener,onListItemClickCallbackListener {
private final String TAG = "MQTT main activity";
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
List<Fragment> fragments;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, StatusListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ServicesListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ConfigFragment.class.getName()));
mAdapter = new TabsPagerAdapter(getSupportFragmentManager(),fragments);
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : MqttApplication.tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
// lock the screen in portrait mode
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void replaceFragmentToServiveListNot() {
fragments.removeAll(fragments);
fragments.add(Fragment.instantiate(this, StatusListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ServiceSpecifNotListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, ConfigFragment.class.getName()));
mAdapter.notifyDataSetChanged();
}
}