I have created an Activity which contains four Floating Button and a fragment which calls Activity's Floating button to make them visible/invisible but when I access these Floating Buttons from fragment it throws null pointer exception.
Activity Code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
getInitialized();
fabSettings = (FloatingActionButton) this.findViewById(R.id.fabSetting);
fabStory = (FloatingActionButton) this.findViewById(R.id.fabStory);
fabImage = (FloatingActionButton) this.findViewById(R.id.fabImage);
fabVideo = (FloatingActionButton) this.findViewById(R.id.fabVideo);
}
Fragment Code:
#SuppressLint("RestrictedApi")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_all_community, container, false);
SessionManager sessionManager = new SessionManager(getActivity());
if(sessionManager.isLoggedIn()){
ActivityUser.fabSettings.setVisibility(View.VISIBLE);
ActivityUser.laySearchCode.setVisibility(View.VISIBLE);
ActivityUser.bottomLayout.setVisibility(View.VISIBLE);
tvCreateCommunity.setVisibility(View.VISIBLE);
}else{
MainActivity.fabSettings.setVisibility(View.VISIBLE);
MainActivity.bottomLayout.setVisibility(View.VISIBLE);
MainActivity.laySearchCode.setVisibility(View.VISIBLE);
((MainActivity) getActivity()).getSupportActionBar().setTitle("");
tvCreateCommunity.setVisibility(View.GONE);
}
}
Please help
Use this code
Fragment:
public class Fragment extends Fragment {
public interface onHideEventListener {
public void hideEvent(boolean isVisible);
}
onHideEventListener hideEventListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
hideEventListener = (onHideEventListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement onHideEventListener");
}
}
final String LOG_TAG = "myLogs";
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment2, null);
SessionManager sessionManager = new SessionManager(getActivity());
if(sessionManager.isLoggedIn()){
hideEventListener.hideEvent(false);
}else{
hideEventListener.hideEvent(true);
}
return v;
}
}
Activity:
public class MainActivity extends Activity implements onSomeEventListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public void hideEvent(boolean isVisible) {
fabSettings.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE);
laySearchCode.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE);
bottomLayout.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE);
}
}
Related
I have 3 fragments where 1 fragment makes changes to the other 2.
The problem is: When I rotate the screen background color and places of fragments 2 and 3 are restored.
I want to keep them without modifying AndroidManifest.xml.
Is it best to use onSaveInstanceState or setRetainInstance or both?
I found some other answers about retaining fragments but none of them were beneficial for my case.
FirstFragment
public class FirstFragment extends Fragment
{
private OnFragmentInteractionListener mListener;
private ChangeColorListener mCallBack;
private boolean clickCheck = false;
public FirstFragment() { }
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_first, container, false);
Button buttonOk = v.findViewById(R.id.button_ok);
Button btn = v.findViewById(R.id.button_replace);
buttonOk.setOnClickListener(v1 -> mCallBack.changeColor(R.color.black));
btn.setOnClickListener(v12 -> {
clickCheck = !clickCheck;
mListener.changeFragment(clickCheck);
});
return v;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState!=null) {
mCallBack =(MainActivity)getActivity();
mListener = (MainActivity)getActivity();
}
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
if (context instanceof ChangeColorListener) {
mCallBack = (ChangeColorListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement ChangeColorListener");
}
try {
mListener = (OnFragmentInteractionListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
}
SecondFragment
public class SecondFragment extends Fragment
{
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_second, container, false);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
}
public void change(int color){
getView().setBackgroundColor(color);
}
}
ThirdFragment
public class ThirdFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_third, container, false);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
}
public void change(int color){
getView().setBackgroundColor(color);
}
}
setRetainInstance() is deprecated. ViewModel is recommended for retaining data across configuration changes.
I have several fragments here and there's this one fragment where I want to save its state when I get back to it. I tried doing it in a testfragment where, when I click the button, the textview text will change to "test1"(The default text of the textview is "New Text"). So the textview changes the text, but when I move into another fragment and get back to it (HomeFragment), the textview is going to its default state text ("New Text"). So I think the savedInstanceState is not working because if it does, it should have "test1" when I get back to the fragment. Here's my code:
public class HomeFragment extends Fragment {
public Button button;
public TextView txt_test;
public String data_test;
public HomeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
return view;
}
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if(savedInstanceState == null){
}
else{
data_test = savedInstanceState.getString("txt_test");
txt_test = (TextView) getActivity().findViewById(R.id.textView2);
txt_test.setText(data_test);
}
button = (Button) getActivity().findViewById(R.id.button3);
txt_test = (TextView) getActivity().findViewById(R.id.textView2);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
txt_test.setText("test1");
}
});
}
public void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("txt_test",data_test);
}
}
public class HomeFragment extends Fragment {
Button button;
TextView txt_test;
String data_test;
public HomeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
txt_test = (TextView) view.findViewById(R.id.textView2);
button = (Button) view.findViewById(R.id.button3);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
txt_test.setText("test1");
}
});
if(savedInstanceState == null) {
// do nothing
} else {
data_test = savedInstanceState.getString("txt_test");
txt_test.setText(data_test);
}
return view;
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("txt_test",data_test);
}
}
I have a fragment which load data from API. I want to show loading progress as google play app does and hide or remove it when it is done.
first off all I don't want to use other libraries(http://johnkil.github.io/Android-ProgressFragment/) for this. I have bunch of code for that. I created a base fragment which show loading. but i am instantiating it in its own class. is it good to work in this way. however the loading implementation works great. MY Loading Fragment is :
public class SpinnerFragment extends Fragment {
private SpinnerFragment spinnerFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_progress, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
spinnerFragment = new SpinnerFragment();
}
/**
* Detach from view.
*/
#Override
public void onDestroyView() {
super.onDestroyView();
}
protected void addSpinner() {
if (!spinnerFragment.isAdded()) {
getFragmentManager().beginTransaction().add(R.id.content_frame, spinnerFragment)
.commit();
}
}
protected void removeSpinner() {
if (spinnerFragment.isAdded()) {
getFragmentManager().beginTransaction().remove(spinnerFragment).commit();
}
}
}
and i am using this class as follow:
public class List extends SpinnerFragment implements View.OnClickListener {
private ListAdapter listAdapter;
private ArrayList<ListRowItem> arrayList;
private ListView listView;
public List() {
}
public static List newInstance() {
List fragment = new List();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(getActivity()));
setRetainInstance(true);
addSpinner();
//loadDataFromWeb
String URL = new SqLite(getActivity()).returnDefaultURI() + "notice/"
new AsyncRequest(onAsyncRequestComplete, getActivity(), "GET", null,
null, 1).execute(URL);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return init(inflater.inflate(R.layout.notice_activity, container, false));
}
private View init(View view) {
listView = (ListView) view.findViewById(R.id.content_container);
listView.setOnScrollListener(onScrollListener());
footer = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.listview_loading_footer, listView, false);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (listAdapter == null && arrayList == null) {
arrayList = new ArrayList<>();
listAdapter = new ListAdapter(getActivity(), arrayList);
listView.setAdapter(listAdapter);
listAdapter.notifyDataSetChanged();
}
}
AsyncRequest.OnAsyncRequestComplete onAsyncRequestComplete = new AsyncRequest
.OnAsyncRequestComplete() {
#Override
public void asyncResponse(final String response, int apiKey) {
switch (apiKey) {
case 1:
//loading complete
listViewBinding(reasponse);
removeSpinner();
break;
}
}
};
}
I want to doing something after pop up disappear in fragment. But, I get error. Please, help me..
Main.java
public class Main extends Fragment implements SendStringEvent{
Button addButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.teacher_category, container, false);
addButton = (Button) rootView.findViewById(R.id.add_category_button);
addButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
TEACHER_AddCategory teacherAddCategory = new TEACHER_AddCategory();
teacherAddCategory.show(getFragmentManager(), "TEACHER_AddCategory");
}
});
return rootView;
}
//This method from interface SendStringEvent
#Override
public void eventAfterMessageClosed(String message) {
//I get error when executing this
addButton.setText(message);
}
}
TEACHER_AddCategory.java (POP UP)
public class TEACHER_AddCategory extends DialogFragment {
Button OKButton;
EditText editText;
private SendStringEvent eventMessageClosed;
Fragment fragment = new Main();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(seamolec.ujianonline.R.layout.teacher_add_category, container);
OKButton = (Button) view.findViewById(seamolec.ujianonline.R.id.ok_button);
try {
eventMessageClosed = (SendStringEvent) fragment;
}
catch(ClassCastException e) {
e.printStackTrace();
}
OKButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
eventMessageClosed.eventAfterMessageClosed("test");
dismiss();
}
}
});
return view;
}
}
This is interface SendStringEvent.java
public interface SendStringEvent {
void eventAfterMessageClosed(String message);
}
I get error when pop up disappear and system is executing "eventAfterMessageClosed()"
Log Cat :
Its happening because you are trying to call the method from a new instance which is not even loaded so view hasn't been created yet.
Change
try {
eventMessageClosed = (SendStringEvent) fragment;
}
catch(ClassCastException e) {
e.printStackTrace();
}
to
Fragment fr = getFragmentManager().findFragmentById(R.id.where_fragment_is_loaded) // Change as per you layout
if(fr != null && fr instanceOf SendStringEvent)
eventMessageClosed = (SendStringEvent) fr;
And change
eventMessageClosed.eventAfterMessageClosed("test");
to
if(eventMessageClosed != null)
eventMessageClosed.eventAfterMessageClosed("test");
NOTE: R.id.where_fragment_is_loaded is indicative. Use the id where you are loading your fragment Main. Also use getSupportFragmentManager() if you are using support library.
I have to add TextViews and EditTexts in a Fragment ( Details() ) when i click in a button ( Button add ).
I was able to insert them, but when i swipe my 6 fragments and return in the first fragment this items disappear.
Can someone help me?
FragmentActivity class:
public class SubActivityTab extends FragmentActivity
{
SectionsPagerAdapter spa;
ViewPager vp;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.scrolltab_layout);
spa = new SectionsPagerAdapter(getSupportFragmentManager(), this);
vp = (ViewPager) findViewById(R.id.pager);
vp.setAdapter(spa);
}
}
FragmentPagerAdapter class:
public class SectionsPagerAdapter extends FragmentPagerAdapter
{
Context c;
public SectionsPagerAdapter(FragmentManager fm, Context c) {
super(fm);
this.c = c;
}
#Override
public Fragment getItem(int position) {
switch(position)
{
case 0:
return Details.newInstance();
...
}
return null;
}
#Override
public int getCount() {
return 6;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position)
{
case 0:
return c.getString(R.string.tab1).toUpperCase(l);
...
}
return null;
}
}
Fragment class:
public final class Details extends Fragment {
public static View layout;
public static LinearLayout ll;
public static Details newInstance()
{
return new Details();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
layout = inflater.inflate(R.layout.details, container, false);
ll = (LinearLayout) layout.findViewById(R.id.linearlayout2);
Button add = (Button) layout.findViewById(R.id.button_add);
add.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
insertLine();
insertClassEditText();
insertLevel();
}});
return layout;
}
private void insertLine()
{
View temp = (View) layout.findViewById(R.id.line);
View v = new View(temp.getContext());
v.setBackgroundColor(Color.rgb(209, 209, 209));
v.setId(0);
v.setLayoutParams(temp.getLayoutParams());
ll.addView(v);
}
private void insertClassEditText()
{
TextView label_classe = (TextView) layout.findViewById(R.id.textView10);
EditText edit_classe = (EditText) layout.findViewById(R.id.editText9);
TextView new_label_classe = new TextView(label_classe.getContext());
EditText new_edit_classe = new EditText(edit_classe.getContext());
new_label_classe.setId(1);
new_edit_classe.setId(2);
new_label_classe.setText("Label");
new_label_classe.setTextAppearance(new_label_classe.getContext(), android.R.style.TextAppearance_Medium);
ll.addView(new_label_classe);
new_edit_classe.setInputType(edit_classe.getInputType());
new_edit_classe.setLayoutParams(edit_classe.getLayoutParams());
ll.addView(new_edit_classe);
}
private void insertLevel()
{
TextView label_lv = (TextView) layout.findViewById(R.id.textView11);
EditText edit_lv = (EditText) layout.findViewById(R.id.editText10);
TextView new_label_lv = new TextView(label_lv.getContext());
EditText new_edit_lv = new EditText(edit_lv.getContext());
new_label_lv.setId(3);
new_edit_lv.setId(4);
new_label_lv.setText(label_lv.getText());
new_label_lv.setTextAppearance(new_label_lv.getContext(), android.R.style.TextAppearance_Medium);
ll.addView(new_label_lv);
new_edit_lv.setInputType(edit_lv.getInputType());
new_edit_lv.setLayoutParams(edit_lv.getLayoutParams());
ll.addView(new_edit_lv);
}
}
I believe ViewPager recycles the views as you swipe and therefore when you go back, it rebuilds from onCreateView.
I would suggest setting some tags and passing to onSaveInstanceState.
private void onSaveInstanceState(Bundle b) {
if (label_classe != null) {
b.putBoolean("label_classe", true);
}
}
Then in onCreateView you take savedInstanceState, check what elements were created and re-create them.
So in Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
....
if (savedInstanceState.getBoolean("label_classe")) {
insertClassEditText();
}
....
}
And just to be sure, in Activity:
public class SubActivityTab extends FragmentActivity
{
SectionsPagerAdapter spa;
ViewPager vp;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.scrolltab_layout);
spa = new SectionsPagerAdapter(getSupportFragmentManager(), this);
vp = (ViewPager) findViewById(R.id.pager);
vp.setSaveState(true);
vp.setSaveFromParentEnabled(true);
vp.setAdapter(spa);
}
}
Try to change your onCreateView method to:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
if(layout ==null){
layout = inflater.inflate(R.layout.details, container, false); //Dont inflate every time.layout saved, data of layout,like EidtText also saved.
}
ViewParent parent = mLayout.getParent();
if(parent!=null){
((ViewGroup)parent).removeView(layout);//the view will be add to NoSaveStateFrameLayout after onCreateView,so remove self everytime
}
return layout;
}