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
Related
I'm trying to add a top toolbar, with an options menu in it, in a fragment. Upon running it on the emulator the toolbar doesn't show up.
I have called setSupportActionBar(toolbar), still not sure what's wrong.
EDIT: I've already changed the app theme to NoActionBar.
ProfileFragment.java
public class ProfileFragment extends Fragment {
private static final String TAG = "ProfileFragment";
private static final int ACTIVITY_NUM = 4;
private Toolbar toolbar;
private BottomNavigationViewEx bottomNavigationView;
private Context mContext;
//firebase
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile, container, false);
toolbar = view.findViewById(R.id.profiletoolbar);
bottomNavigationView = view.findViewById(R.id.bottomnav);
mContext = getActivity();
Log.d(TAG, "onCreateView: started.");
setupBottomNavigationView();
setupToolBar();
return view;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
setHasOptionsMenu(true);
super.onCreate(savedInstanceState);
}
//bottom nav setup
public void setupBottomNavigationView() {
Log.d(TAG, "setupBottomNavigationView: starting bottomnavsetup");
BottomNavigationViewHelper.setupBottomNavigationView(bottomNavigationView);
BottomNavigationViewHelper.enableBottomNav(mContext, bottomNavigationView);
Menu menu = bottomNavigationView.getMenu();
MenuItem menuItem = menu.getItem(ACTIVITY_NUM);
menuItem.setChecked(true);
}
//toolbar setup
private void setupToolBar() {
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.signout) {
Toast.makeText(mContext, "Sign out clicked", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onOptionsItemSelected: attempting to sign out");
mAuth.signOut();
getActivity().finish();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
menuInflater.inflate(R.menu.profile_menu, menu);
super.onCreateOptionsMenu(menu, menuInflater);
}
}
snippet_top_profile_bar.xml (This is the toolbar)
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/white_grey_border_bottom">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/profiletoolbar">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="#username"
android:id="#+id/username"/>
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
I have all the necessary imports.
This method will work in Activity. But, here you are trying to do it with Fragment. fragments are sub activities so they have limited scope to do things.
Another thing that may happen, You should change the Activity theme to noActionbar.
By using this, default toolbar will be hide your custom toolbar will be displayed.
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 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>
I am using a searchview inside fragment and getting a nullpointerexception.
I don't understand why, I'm just trying to get the query...
I'm using a 3 tab fragment and the app crash when launching
MainActivity.java
public class MainActivity extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Search", "Top", "Download", "Library" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initilization
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) {
}
}
SearchFragment.java
public class SearchFragment extends Fragment {
private SearchView searchView1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_search, container, false);
searchView1 = (SearchView) getActivity().findViewById(R.id.searchView1);
final SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextChange(String newText) {
// Do something
return true;
}
#Override
public boolean onQueryTextSubmit(String query) {
// Do something
performSearch();
return true;
}
};
searchView1.setOnQueryTextListener(queryTextListener);
return rootView;
}
public void performSearch(){
Toast.makeText(getActivity(), "search performer", Toast.LENGTH_SHORT).show();
}
}
fragment_search.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#17df0d">
<SearchView
android:id="#+id/searchView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:iconifiedByDefault="false"
android:queryHint="#string/search_hint" >
</SearchView>
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/searchView1" >
</ListView>
</RelativeLayout>
Can you please tell me what i'm doing wrong and how could I succeed?
You should look for the search view in your fragment's view, not in your activity's view.
Change
searchView1 = (SearchView) getActivity().findViewById(R.id.searchView1);
to
searchView1 = (SearchView) rootView.findViewById(R.id.searchView1);
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();
}
}