I am developing an app under MVP architecture as well I am using DataBinding. I have a ViewPager and in the first view-page fragment there are a few TexViews
This is my first Fragment, inside the ViewPager, who has the TextViews, note that setText() method just works on my bind() method but does not work outsite of it.
public class ViewPagerFragmentMe extends BaseFragment implements ViewPagerFragmentMeView {
private ViewPagerFragmentMePresenter mPresenter;
private FragmentViewPagerMeBinding mFragmentBinding;
private TextView mFollowers;
private TextView mFollowing;
private TextView mPost;
#Override
protected View getBindView(LayoutInflater inflater, ViewGroup container) {
mFragmentBinding = DataBindingUtil.inflate(inflater,
R.layout.fragment_view_pager_me,container,false);
View view = mFragmentBinding.getRoot();
bind(mFragmentBinding);
return view;
}
#Override
protected void getPresenter() {
Log.d(Constans.LOG,"GET PRESENTER CALLED");
mPresenter = new ViewPagerFragmentMePresenterImpl(this);
mFollowers.setText("2");//does not work
startSocialCounterUp(3,mFollowers);
}
#Override
public void startSocialCounterUp(int number, TextView textView) {
mPresenter.onSetNumberCounterUp(number,textView);
mFollowers.setText(String.valueOf(number));//does not work
}
private void bind(FragmentViewPagerMeBinding binder) {
mFollowers = binder.textViewPagerFollowersNumber;
mFollowing = binder.textViewPagerFollowingNumber;
mPost = binder.textViewPagerPostNumber;
mFollowers.setText("1");//works
}
}
This my BaseFragment
public abstract class BaseFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View view = getBindView(inflater,container);
getBindView(inflater, container);
getPresenter();
return view;
}
protected abstract View getBindView(LayoutInflater inflater, ViewGroup container);
protected abstract void getPresenter();
}
and finally my MVP view with the fragment related
public interface ViewPagerFragmentMeView {
void startSocialCounterUp(int number, TextView textView);
}
Is quite strange. Is not it? What I am doing wrong?
Related
I am making a bugtracker app on android where i have a class called Task, which has a field "category" which defines if the task is done, in progress or have to do.
I have a fragment of ideas "Projects" where I added to set the ViewModel
public class ProjectFragment extends Fragment {
private static final String TAG = "ProjectFragment";
private UserViewModel model;
private GridViewAdapter gridViewAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_projects, container, false);
model = ViewModelProviders.of(requireActivity()).get(UserViewModel.class);
GridView gridView = view.findViewById(R.id.gridview_project);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Project temp = Objects.requireNonNull(model.getCurrentuser().getValue()).getProjects().get(position);
model.setCurrproject(temp);
Log.i(TAG, "onItemClick: " + temp.getProjectName());
model.setTodoTasks(TaskSorter.getSortedTaskList(temp, "TODO"));
model.setInprogressTasks(TaskSorter.getSortedTaskList(temp, "IN PROGRESS"));
model.setDoneTasks(TaskSorter.getSortedTaskList(temp, "DONE"));
}
});
gridViewAdapter = new GridViewAdapter(requireActivity(), Objects.requireNonNull(model.getCurrentuser().getValue()).getProjects());
gridView.setAdapter(gridViewAdapter);
model.getCurrentuser().observe(this, new Observer<User>() {
#Override
public void onChanged(User user) {
gridViewAdapter.notifyDataSetChanged();
}
});
FloatingActionButton floatingActionButton = view.findViewById(R.id.floatingActionButton);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openProjectDialog();
}
});
return view;
}
I also have 3 fragment for the corresponding categories where I observe the changes.
public class FragmentToDo extends Fragment {
private static final String TAG = "FragmentToDo";
private ListView listView;
private UserViewModel model;
private ListViewAdapter listViewAdaptertodo;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_todo, container, false);
listView = view.findViewById(R.id.todo_list);
model = ViewModelProviders.of(this).get(UserViewModel.class);
model.gettodoTasks().observe(this, new Observer<ArrayList<Task>>() {
#Override
public void onChanged(ArrayList<Task> tasks) {
listViewAdaptertodo.notifyDataSetChanged();
Log.i(TAG, "onChanged: todo");
}
});
initTodo();
return view;
}
private void initTodo(){
listViewAdaptertodo = new ListViewAdapter(requireActivity(), model.gettodoTasks().getValue());
listView.setAdapter(listViewAdaptertodo);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
openTask();
}
});
}
All the 3 fragments looks like this, with different names of course. Whenever I click on a project some change happen, but not in all of them. The 3 categories are hold by a ViewPager, but im not sure where the problem is. In case heres the code for that too:
public class TaskFragment extends Fragment {
private static SectionsPagerAdapter sectionsPagerAdapter;
private ArrayList<Task> todo;
private ArrayList<Task> inp;
private ArrayList<Task> done;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_task, container, false);
sectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
sectionsPagerAdapter.addFragments(new FragmentToDo(), "To Do");
sectionsPagerAdapter.addFragments(new FragmentInProgress(), "In Progress");
sectionsPagerAdapter.addFragments(new FragmentDone(), "Done");
ViewPager viewPager = view.findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = view.findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
return view;
}
}
Maybe the problem is whenever I define context and lifecycle owners, because as I am a novice android developer, i still know few thing about these topics.
There is simple and not extensible way - eventbus, this, for example.
And preferred way- move your app logic from fragments to other components, with data passing only in 1 way. I.e there is component, that exposes some sort of model of your screen, that get's updated - and fragment/view/activity reflect that change. You can check sample app here
I already implemented a code from another tutorial but I don't know how to change the TextView with this code. I know that I have to use the setAnswer of the ViewModel but I don't know where to use it. I am relatively new to programming so your help is much appreciated! After the first question there are 2 other question each with a EditText that's input should also be displayed in the next fragment of the question.
Here is my ViewModel:
public class SharedViewModel extends ViewModel {
public HashMap<Integer, MutableLiveData<String>> answers = new HashMap<Integer, MutableLiveData<String>>(){{
put(1, new MutableLiveData<String>());
put(2, new MutableLiveData<String>());
put(3, new MutableLiveData<String>());
}};
public MutableLiveData<String> getAnswer(int questionId) {
return answers.get(questionId);
}
public void setAnswer(int questionId, String answer) {
if (answers.get(questionId) != null) {
answers.get(questionId).setValue(answer);
}
}
}
Here is my Fragment with the EditText:
public class FragmentQuestion1 extends Fragment {
private Button btnNavFrag1;
private EditText mEditTextQuestion1;
private SharedViewModel viewModel;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_question_1, container, false);
btnNavFrag1 = view.findViewById(R.id.btn_question1);
mEditTextQuestion1 = view.findViewById(R.id.edit_text_question_1);
mEditTextQuestion1.addTextChangedListener(new NumberTextWatcher(mEditTextQuestion1));
m_bar = view.findViewById(R.id.progress_bar_question_1);
btnNavFrag1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewModel.getAnswer(1);
((GameActivity)getActivity()).setViewPager(2);
}
});
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
viewModel.getAnswer(1).observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String answer) {
tv_answer1.setText(answer);
}
});
}
And here is my second Fragment where the input of the previous EditText should be displayed in a TextView:
public class FragmentAnswer1 extends Fragment {
private View btnNavFragAns1;
private TextView tv_answer1;
private SharedViewModel viewModel;
#Nullable
#Override
public View onCreateView( LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_question_answer_1, container, false);
btnNavFragAns1 = view.findViewById(R.id.next_question_1);
tv_answer1 = view.findViewById(R.id.answer_player_1_text_view);
btnNavFragAns1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
((GameActivity)getActivity()).setViewPager(3);
}
});
return view;
}
#Override
public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle);
viewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
viewModel.getAnswer(1).observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String answer) {
tv_answer1.setText(answer);
}
});
}
}
Create a global variable(String) to store the text of your EdiText
When you open the Fragment with your EditText you can use a Button (onClickListener) or onDetached to set your global variable.
((MyApplication) this.getApplication()).setSomeVariable(edittext.getText().toString());
When you go back to your Fragment with the TextView, you add this to void onStart()
textview.setText(((MyApplication) this.getApplication()).getSomeVariable());
I am a beginner in android development and I want to navigate to an activity from a fragment when an image in ImageView is clicked. My Java class does not let me declare variables to link to my XML file. Also, I am not sure as to in which java class I should be declaring my variables.
I have also tried writing the same code in my MainActivity but it still shows an error.
public class HomeFragment extends Fragment{
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable
ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home,container,false);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
edSheeranSongs = (ImageView)findViewById(R.id.ed_sheeran);
justinBieberSongs = (ImageView)findViewById(R.id.justin_bieber);
shawnMendesSongs = (ImageView)findViewById(R.id.shawn_mendes);
edSheeranSongs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(),SheeranSongs.class);
startActivity(intent);
}
});
I expect to go to another activity which I have already created called SheeranSongs, But I get an error message when I try to declare anything in a fragment
You should inflate the view in onCreateView of the fragment and initilize views with the created custom view. Override onAttach to get the context of the activivty to which the fragment is attached to.
public class HomeFragment extends Fragment{
private Context context;
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context=context;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
edSheeranSongs = view.findViewById(R.id.ed_sheeran);
justinBieberSongs = view.findViewById(R.id.justin_bieber);
shawnMendesSongs = view.findViewById(R.id.shawn_mendes);
edSheeranSongs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context, SheeranSongs.class);
startActivity(intent);
}
});
return view;
}
}
You should call findViewById() from the inflated view within onCreateView of the Fragment. Exapmle:
public class HomeFragment extends Fragment{
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
edSheeranSongs = view.findViewById(R.id.ed_sheeran);
justinBieberSongs = view.findViewById(R.id.justin_bieber);
shawnMendesSongs = view.findViewById(R.id.shawn_mendes);
edSheeranSongs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(requireContext(), SheeranSongs.class);
startActivity(intent);
}
});
return view;
}
}
When working with fragment you can't call findviewbyid() in onCreate() as you do in Activity since the fragment is created in onCreate() but the user interface isn't drawn yet (More about fragment).
You can do it in onCreateView() or onViewCreated(). From my perspective, I do it in onViewCreated() so it looks a bit cleaner.
public class HomeFragment extends Fragment{
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home,container,false);
}
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView edSheeranSongs = view.findViewById(R.id.ed_sheeran);
ImageView justinBieberSongs = view.findViewById(R.id.justin_bieber);
ImageView shawnMendesSongs = view.findViewById(R.id.shawn_mendes);
edSheeranSongs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(requireActivity(), SheeranSongs.class);
startActivity(intent);
}
});
}
//This is the TextViewExample class
public class TextViewExample {
private TextView mTextViewExample;
public TextViewExample(Activity activity) {
mActivity = activity;
mTextViewExample = (TextView)mActivity.findViewById(R.id.TextViewLayout);
}
}
//This is the Fragment class
public class TextViewFragment extends Fragment {
private TextViewExample mText;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mText = new TextViewExample(getActivity());
}
}
mText is not updated in the UI! Could someone explain the correct way of displaying TextView properly from calling an activity in a fragment.
Thanks =)
You can access the Activity's TextView in the Fragment (assuming this fragment is attached to the activity) directly:
//This is the Fragment class
public class TextViewFragment extends Fragment {
private TextView mText;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// you need to inflate the xml file holding this TextView.
mText = (TextView) getActivity().findViewByid(R.id.<your-text-view-id>;
// do something with your TextView
}
}
Be sure to check for getActivity() == null to avoid NPE's.
Activity:
public class MainActivity {
private TextView mTextViewExample;
protected void onCreate(Bundle savedInstanceState) {
...
mTextViewExample = (TextView) findViewById(R.id.TextViewLayout);
}
}
public void setTextViewExampleText(String text) {
mTextViewExample.setText(text);
}
TextViewFragment
public class TextViewFragment extends Fragment {
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
((MainActivity) getActivity()).setTextViewExampleText("text");
}
}
i have first fragment and second fragment i want from the second fragment to make some thing in the frist fragent using callback with interface but i find this error
java.lang.NullPointerException: Attempt to invoke interface method
interface:
public interface MyProfileCallback
{
void callbackCall(Context con);
}
first fragment:
public class firstfragment extends Fragment implements MyProfileCallback
{
public firstfragment()
{
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View rootview = inflater.inflate(R.layout.fisrt, container, false);
/
...
/
}
#Override
public void callbackCall(Context con)
{
Toast.makeText(getActivity(), "calllllllllll baaaaaaaaaaaaack",
Toast.LENGTH_SHORT).show();
}
}
second fragment:
public class secondfragment extends Fragment
{
MyProfileCallback mcallback;
public secondfragment()
{
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View rootview = inflater.inflate(R.layout.second, container, false);
mcallback.callbackCall(getContext());
return rootview;
}
Add this in your second Fragment,
mcallback=refernce of your First Frgament;
And Call this method:
mcallback.callbackCall(getContext());