I'm using a FragmentStatePagerAdapter (for the ViewPager), The fragments which are attached to the ViewPager have fields which I wish to pass the data back to the Activity. My problem lies in that the interface objects which I pass to the fragments are lost once the device has been rotated.
My question is how do I retain the interface objects.
Now the obligatory code snippets:
The Activity:
public class TheActivity extends AppCompatActivity {
static final int PageCount = 2;
static final int PageA = 0;
static final int PageB = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
#Override
public Fragment getItem(int position) {
switch (position) {
case PageA: {
PageAFragment fragment = PageAFragment.CreateFragment();
fragment.setDataListener(new PageAFragment.DataListener() {
#Override
public void OnPageADataChange(String value) {
PageAData = value;
}
});
return fragment;
}
case PageB: {
PageBFragment fragment = PageBFragment.CreateFragment(2);
fragment.setDataListener(new PageBFragment.DataListener() {
#Override
public void OnPageAOneDataChange(String value) {
PageBDataOne = value;
}
#Override
public void OnPageATwoDataChange(String value) {
PageBDataTwo = value;
}
});
return fragment;
}
}
return null;
}
#Override
public int getCount() {
return PageCount;
}
});
}
}
The Fragments:
public class PageAFragment extends Fragment {
private DataListener mListener;
public static PageAFragment CreateFragment() {
return new PageAFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.page_a, container, false);
EditText editText = (EditText) view.findViewById(R.id.edittext_data_a);
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionID, KeyEvent event) {
if (actionID == EditorInfo.IME_ACTION_DONE)
mListener.OnPageADataChange(editText.getText().toString());
return false;
}
});
return view;
}
public void setDataListener(DataListener dataListener) {
mListener = dataListener;
}
public interface DataListener {
void OnPageADataChange(String value);
}
}
public class PageBFragment extends Fragment {
private DataListener mListener;
public static PageBFragment CreateFragment(int data) {
PageBFragment fragment = new PageBFragment();
Bundle bundle = new Bundle();
bundle.putInt("Data", data);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.page_b, container, false);
EditText editTextOne = (EditText) view.findViewById(R.id.edittext_data_b_one);
editTextOne.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionID, KeyEvent event) {
if (actionID == EditorInfo.IME_ACTION_DONE)
mListener.OnPageAOneDataChange(editTextOne.getText().toString());
return false;
}
});
EditText editTextTwo = (EditText) view.findViewById(R.id.edittext_data_b_two);
editTextTwo.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionID, KeyEvent event) {
if (actionID == EditorInfo.IME_ACTION_DONE)
mListener.OnPageATwoDataChange(editTextTwo.getText().toString());
return false;
}
});
return view;
}
public void setDataListener(DataListener dataListener) {
mListener = dataListener;
}
public interface DataListener {
void OnPageAOneDataChange(String value);
void OnPageATwoDataChange(String value);
}
}
I think you should re read this https://developer.android.com/training/basics/fragments/communicating.html.
Let the activity implement the interfaces and use the onAttach() onDetach() methods to reset the reference of the callback to the activity.
With your code if you try to retain the fragments' state (setRetainInstance(true), onsaveInstanceState()) which includes the interface objects you will probably have issues with memory leak or your code will become too complicated for no reason.
Related
My app creates drawer submenus from sharedpreference values. These submenus are basically called "interests" or categories. I'm trying to move this same functionality to tablayout since that is much more convenient but can't seem to get it to work!
Edit: New code based on suggestions.
TabsFragment:
public class HomeTabsFragment extends Fragment implements ViewPager.OnPageChangeListener {
private View view;
private SectionsPagerAdapterHome homePageAdapter;
public ViewPager viewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.view = inflater.inflate(R.layout.fragment_articles_tabs, container, false);
TabLayout tabLayout = view.findViewById(R.id.home_list_tabs);
viewPager = view.findViewById(R.id.home_list_tabs_container);
homePageAdapter = new SectionsPagerAdapterHome(getFragmentManager());
viewPager.setAdapter(homePageAdapter);
viewPager.setOffscreenPageLimit(tabLayout.getTabCount());
viewPager.addOnPageChangeListener(this);
tabLayout.setupWithViewPager(viewPager);
if(SharedPrefernces.getUserInterests()!=null) {
List<String> my_interests = SharedPrefernces.getUserInterests();
Collections.sort(my_interests, String::compareToIgnoreCase);
my_interests.add(0, getString(R.string.all_stories));
for (String interest : my_interests) {
homePageAdapter.addTabPage(new FeedsFragment(), interest);
}
}
return view;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Do something that differs the Activity's menu here
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return false;
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
Fragment fragment = homePageAdapter.getFragment(position);
if (fragment != null) {
fragment.onResume();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
}
Adapter:
public class SectionsPagerAdapterHome extends FragmentPagerAdapter {
private FragmentManager fragmentManager;
private ArrayList fragmentTags = new ArrayList();
private ArrayList<String> titles = new ArrayList();
protected SectionsPagerAdapterHome(FragmentManager fm) {
super(fm, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
fragmentManager = fm;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object object = super.instantiateItem(container, position);
if (object instanceof Fragment) {
Fragment fragment = (Fragment) object;
String tag = fragment.getTag();
fragmentTags.add(position, tag);
}
return object;
}
public Fragment getFragment(int position) {
Fragment fragment = null;
Object tag = fragmentTags.get(position);
if (tag != null) {
fragment = fragmentManager.findFragmentByTag(String.valueOf(tag));
}
return fragment;
}
#Override
public Fragment getItem(int position) {
return FeedsFragment.newInstance();
}
public void addTabPage(Fragment fragment,String title) {
titles.add(title);
fragmentTags.add(fragment);
notifyDataSetChanged();
}
#Override
public int getCount() {
return fragmentTags.size();
}
#Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
}
I'm not sure how I can achieve this so need help.
Since you are using a ViewPager with an Adapter instead of using tabLayout.addTab(...) you have to add the item in the adapter.
Something like:
public class SectionsPagerAdapterHome extends FragmentPagerAdapter {
private ArrayList fragmentTags = new ArrayList();
private ArrayList<String> titles = new ArrayList();
//.....
public void addTabPage(Fragment fragment,String title) {
titles.add(title);
fragmentTags.add(fragment);
notifyDataSetChanged();
}
#Override
public int getCount() {
return fragmentTags.size();
}
#Override
public CharSequence getPageTitle(int position) {
return tables.get(position);
}
}
I have created tabbed activity, which has viewpager with two instances of one fragment class. This fragment contains listbox, and I have written few functions to
interact with listview items, and one function in activity to do the same thing. The point is when im trying to call fragment methods, it always trying to update the listview of fragment, which was created at first, but when i call function from activity it works absolutely correct. Whats the problem?
Here is the code of activity:
public class CategoriesActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
SparseArray<Fragment> registeredFragments = new SparseArray<>();
Toolbar toolbar;
FloatingActionButton btnAddCategories;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_categories);
assignElements();
prepareToolbar();
prepareEelements();
}
public void assignElements() {
toolbar = findViewById(R.id.action_bar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
btnAddCategories = findViewById(R.id.btnAddCategory);
// Set up the ViewPager with the sections adapter.
mViewPager = findViewById(R.id.container);
}
public void prepareToolbar() {
toolbar.setTitle("Категории");
toolbar.setTitleTextColor(getResources().getColor(R.color.colorTextLight));
toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
public void prepareEelements() {
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
btnAddCategories.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TabCategoriesFragment tabCategoriesFragment = (TabCategoriesFragment) getRegisteredFragment(mViewPager.getCurrentItem());
tabCategoriesFragment.addNewCategory();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case R.id.home:
finish();
break;
case R.id.homeAsUp:
finish();
break;
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = TabCategoriesFragment.newInstance(false);
break;
case 1:
fragment = TabCategoriesFragment.newInstance(true);
break;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
}
}
And of the fragment:
public class TabCategoriesFragment extends Fragment {
private static final String ARG_INCOMING = "Incoming";
private OnFragmentInteractionListener mListener;
public int Incoming = -1;
ListView listView;
ArrayList<Categories> categories;
CategoriesListViewAdapter categoriesListViewAdapter;
DBHelper dbHelper;
SQLiteDatabase sqLiteDatabase;
public TabCategoriesFragment() {
}
public int selectedPostion;
public static TabCategoriesFragment newInstance(boolean Incoming) {
TabCategoriesFragment fragment = new TabCategoriesFragment();
Bundle args = new Bundle();
args.putBoolean(ARG_INCOMING, Incoming);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
if (getArguments().getBoolean(ARG_INCOMING)) {
Incoming = 1;
} else {
Incoming = 0;
}
}
}
public void assignElements(View view) {
dbHelper = new DBHelper(getContext());
sqLiteDatabase = dbHelper.getWritableDatabase();
categories = new ArrayList<>();
categoriesListViewAdapter = new CategoriesListViewAdapter(getContext(), categories);
}
#SuppressLint("ClickableViewAccessibility")
public void prepareElements() {
filldata();
listView.setAdapter(categoriesListViewAdapter);
categoriesListViewAdapter.notifyDataSetChanged();
registerForContextMenu(listView);
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
selectedPostion = position;
getActivity().openContextMenu(listView);
return true;
}
});
}
public void deleteCategory(boolean deletecosts, String name) {
try {
//delete from db
} catch (Exception e) {
Toast.makeText(getContext(), "Произошла ошибка" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
public String getTableName() {
if (Incoming == 1) {
return "incomingcategories";
} else {
return "outcomingcategories";
}
}
public String getSign() {
if (Incoming == 1) {
return ">";
} else {
return "<";
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Objects.requireNonNull(getActivity()).getMenuInflater().inflate(R.menu.edit_category_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
//final int selectedPostion = ((AdapterView.AdapterContextMenuInfo) item.getMenuInfo()).position;
int id = item.getItemId();
final CheckBox checkBox = new CheckBox(getContext());
switch (id) {
case R.id.categoryDelete:
deleteCategory(categories.get(selectedPosition);
filldata();
categoriesListViewAdapter.notifyDataSetChanged();
case R.id.categorySetbydefault:
break;
case R.id.categoriesSetBydefault:
setCategoryBydefault(categories.get(selectedPostion).description);
filldata();
categoriesListViewAdapter.notifyDataSetChanged();
break;
}
return true;
}
public void setCategoryBydefault(String name) {
//set
}
#Override
public void onStart() {
super.onStart();
prepareElements();
CategoriesActivity categoriesActivity = (CategoriesActivity) getActivity();
}
public void filldata() {
categories.clear();
//do some stuff
}
public void addNewCategory() {
//do some stuff
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tab_categories, container, false);
listView = view.findViewById(R.id.CategoriesListView);
assignElements(view);
return view;
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
}
My viewpager adapter is in another fragment(i.e. in main fragment) i.e. i used viewpager in another fragment.so viewpager adapter having 2 fragments.
I am getting heart rate value continuously from main fragment and need to send it to viewpager adapter.then viewpager adapter send this value to fragment and upadate the textview here.
//Main Fragment were i initialize fragmentpageradapter with updated heart rate value:-((readingdata)samplePagerAdapter).passdata(value);
used interface to update value:-
public interface readingdata
{
void passdata(int value);
}
//Adapter code:-
public class SamplePagerAdapter extends FragmentStatePagerAdapter implements readingdata {
private final Random random = new Random();
private int mSize = 2;
private int heart_rate;
FragmentManager fm;
private Map<Integer, String> mFragmentTags;
public SamplePagerAdapter(FragmentActivity activity, FragmentManager supportFragmentManager, int heart) {
super(supportFragmentManager);
fm = supportFragmentManager;
mFragmentTags = new HashMap<Integer, String>();
}
#Override
public int getCount() {
return mSize;
}
#Override
public Fragment getItem(int position) {
Fragment f = null;
if (position == 0) {
f = new MyFragment().newInstance(heart_rate);
} else if (position == 1) {
f = new SecondFragment();
}
return f;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object object = super.instantiateItem(container, position);
if (object instanceof Fragment) {
Fragment fragment = (Fragment) object;
String tag = fragment.getTag();
mFragmentTags.put(position, tag);
}
return object;
}
public Fragment getFragment(int position) {
Fragment fragment = null;
String tag = mFragmentTags.get(position);
if (tag != null) {
fragment = fm.findFragmentByTag(tag);
}
return fragment;
}
#Override
public void passdata(int value) {
heart_rate=value;
}
}
//Fragment code were textview updated on regular interval
public class MyFragment extends Fragment{
private int heart_rate;
private ArcProgress arc_progress;
private TextView tv_heartrate;
private Handler handler;
private Runnable runnable;
private View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveBundle) {
view = inflater.inflate(R.layout.ecg_layout, container, false);
handler=new Handler();
arc_progress = (ArcProgress) view.findViewById(R.id.arc_progress);
tv_heartrate = (TextView) view.findViewById(R.id.tv_heart_rate);
handler=new Handler();
handler.post(runnable = new Runnable() {
#Override
public void run() {
MyFragment myFragment=new MyFragment();
arc_progress.setProgress(heart_rate);
tv_heartrate.setText(String.valueOf(heart_rate));
handler.postDelayed(this, 1000);
}
});
return view;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
public static Fragment newInstance(int heartvalue) {
MyFragment f = new MyFragment();
f.heart_rate = heartvalue;
return f;
}
}
So how should i update textview continuously inside the fragment?
In MainFragment
private static HeartRateListener heartRateListener;
public static void setHeartRateListener(HeartRateListener listener){
heartRateListener = listener;
}
public static interface HeartRateListener{
void onHeartRate(int yourValue);
}
// Send your continuously updated value
heartRateListener.onHeartRate(yourValue);
In ViewPager Fragment (inside onViewCreated())
MainFragment.setHeartRateListener(new MainFragment.HeartRateListener() {
#Override
public void onHeartRate(int yourValue) {
// Update your textview with yourValue
}
});
create Method
public void updateScreenData(String text)
{
tv_heartrate.setText(text);
}
in fragment and then call this method from activity
make sure that fragment reference is not null whenever call this method
Take Help from this and save reference to view you are inflating
package com.mtg.workapp_v2.listing.wanted.add_wanted;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import com.mtg.classes.AddressView;
import com.mtg.classes.ListingVisibilityLayout;
import com.mtg.utils.CommonMethods;
import com.mtg.workapp.R;
public class WantedBasicInfoFragment extends Fragment implements View.OnClickListener{
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
View FragmentView ;
Context myContext;
TextView text_continue;
EditText edit_title;
EditText edit_description;
private OnFragmentInteractionListener mListener;
//this is add by ahsan according to new design
ListingVisibilityLayout listingVisibilityLayout = null;
public WantedBasicInfoFragment() {
}
public static WantedBasicInfoFragment newInstance(String param1, String param2) {
WantedBasicInfoFragment fragment = new WantedBasicInfoFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
FragmentView= inflater.inflate(R.layout.fragment_wanted_basic, container, false);
init();
return FragmentView;
}
/********************************************************************************/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
/********************************************************************************/
public void setListener(OnFragmentInteractionListener listener) {
this.mListener = listener;
}
/********************************************************************************/
public void setInitValues()
{
}
/***********************************************************************************/
public void updateScreenData()
{
edit_title.setText(wantedInformation.csName);
edit_description.setText(wantedInformation.csDescription);
}
/***********************************************************************************/
public void init()
{
myContext=getActivity();
text_continue=(TextView) FragmentView.findViewById(R.id.text_continue);
edit_title = (EditText) FragmentView.findViewById(R.id.edit_title);
edit_description = (EditText) FragmentView.findViewById(R.id.edit_description);
text_continue.setOnClickListener(this);
edit_title.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
wantedInformation.csListingLanguage = CommonMethods.getInputLanguage(myContext);
}
#Override
public void afterTextChanged(Editable s) {
wantedInformation.csListingLanguage = CommonMethods.getInputLanguage(myContext);
}
});
initVisibilitySpinner();
}
/***********************************************************************************/
public void initVisibilitySpinner()
{
listingVisibilityLayout = new ListingVisibilityLayout(myContext);
View visibilityView = (View)FragmentView.findViewById(R.id.id_visibility_layout);
listingVisibilityLayout.ListingVisibilityInit(visibilityView);
}
/***********************************************************************************/
#Override
public void onClick(View view) {
int itemID = view.getId();
switch (itemID) {
case R.id.text_continue:
{
moveToNextScreen(true);
}
}
}
/***********************************************************************************/
public void moveToNextScreen(boolean isContinueClicked)
{
String csName = edit_title.getText().toString().trim();
String csDescription = edit_description.getText().toString().trim();
if(csName.length() <= 0 && csDescription.toString().length() <= 0)
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_please_enter_name_and_description), myContext);
return;
}
else if(csName.length() <= 0)
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_please_enter_name), myContext);
return;
}
else if(csDescription.length() <= 0)
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_please_enter_description), myContext);
return;
}
else if(listingVisibilityLayout.selectedProfileVisibility.csOptionID.equalsIgnoreCase("-1"))
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_select_visibility_option_msg), myContext);
return;
}
wantedInformation.csName = csName;
wantedInformation.csDescription = csDescription;
wantedInformation.visibilityOption = listingVisibilityLayout.selectedProfileVisibility;
//MH: If continue clicked then continue Button listener will be called
//MH: If only tick is clicked in Edit Mode then onUpdate listener will be called
//MH: and data will be updated before sent to api
//MH: The below statements are repeated in all fragments of Wanted
if(isContinueClicked)
mListener.continueButtonPressed(wantedInformation);
else
mListener.onUpdate(wantedInformation);
}
}
I have ViewPager that is showing fragments : SearchFragment,FriendFragment. What I am struggling to do is to change SearchFragment to ChatFragment
There is a lot of feedback in replace-fragment-inside-a-viewpager/ yet I have some trouble with making any of these solutions work.
I think there might be something wrong with my way of creating interface, I had some trouble to make it callable from ViewPager as SearchActivity.newInstance(new MyListener {...} )
I reached the point now where I get
java.lang.NullPointerException: Attempt to invoke virtual method
'android.support.v4.app.FragmentTransaction
android.support.v4.app.FragmentManager.beginTransaction()' on a null
object reference
at
com.example.ashaneen.firebaseapp.adapters.MainScreenAdapter$1.onFragmentChange(MainScreenAdapter.java:44)
at
com.example.ashaneen.firebaseapp.fragments.SearchFragment$4.onComplete(SearchFragment.java:132)
MainScreenAdapter.class
public class MainScreenAdapter extends FragmentPagerAdapter implements SearchFragment.MyListener {
private static final String TAG = "MainScreenAdapter";
private FragmentManager fragmentManager;
private Fragment fragment1;
public MainScreenAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position)
{
switch (position)
{
case 0:
if (fragment1 == null)
{
fragment1 = SearchFragment.newInstance(new SearchFragment.MyListener() {
#Override
public void onFragmentChange() {
fragmentManager.beginTransaction().remove(fragment1).commit();
fragment1 = ChatFragment.newInstance();
notifyDataSetChanged();
}
});
}
return fragment1;
case 1:
return new FriendsFragment();
default:
return new ChatFragment();
}
}
#Override
public int getItemPosition(#NonNull Object object) {
return POSITION_NONE;
}
#Override
public void onFragmentChange() {
}
SearchFragment.class
public class SearchFragment extends android.support.v4.app.Fragment {
public SearchFragment() {
}
private String TAG = "Profile2Fragment";
public interface MyListener
{
void onFragmentChange();
}
static MyListener myListener = new MyListener() {
public void onFragmentChange() {
}
};
public static SearchFragment newInstance(MyListener myListener) {
SearchFragment.myListener = myListener;
return new SearchFragment();
}
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_search, container, false);
button = view.findViewById(R.id.btn_search);
waitingRoomReference = db.collection("awaiting_room");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
myListener.onFragmentChange();
}
}
});
return view;
}
Try changing this
public MainScreenAdapter(FragmentManager fm) {
super(fm);
}
to
public MainScreenAdapter(FragmentManager fm) {
super(fm);
fragmentManager = fm;
}
Movie ListView Fragment
Movie Info Fragment
What I have is an app that has a database of movies, in my first tab fragment I have a listview which has all the movies in my database. I want it so when I click a movie in the listview it grabs the movie's database id and moves to the next tab which displays the movie info.
Main Activity (The activity that holds my tabs view pager)
public class MainActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setOffscreenPageLimit(1);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
}
#Override
public boolean onCreateOptionsMenu (Menu menu){
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected (MenuItem item){
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public static class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new FragmentMain();
case 1:
return new FragmentManuallyAddMovie();
case 2:
return new FragmentAddInternetMovie();
}
return null;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "MOVIES";
case 1:
return "ADD";
case 2:
return "SEARCH";
}
return null;
}
}
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
FragmentMain (Where the movies database is displayed in a listview)
public class FragmentMain extends Fragment implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, View.OnClickListener {
private MoviesDBHandler handler;
private SimpleCursorAdapter adapter;
private ListView lvMovies;
public FragmentMain() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
handler = new MoviesDBHandler(this.getActivity());
v.findViewById(R.id.btn_delete_all_movies).setOnClickListener(this);
lvMovies = (ListView) v.findViewById(R.id.lv_movies);
lvMovies.setEmptyView(v.findViewById(R.id.tv_instructionsa));
lvMovies.setOnItemClickListener(this);
lvMovies.setOnItemLongClickListener(this);
return v;
}
#Override
public void onResume() {
super.onResume();
String[] from = {MoviesDBHelper.MOVIES_TITLE, MoviesDBHelper.MOVIES_GENRE, MoviesDBHelper.MOVIES_YEAR, MoviesDBHelper.MOVIES_PLOT, MoviesDBHelper.MOVIES_RATING, MoviesDBHelper.MOVIES_RUNTIME, MoviesDBHelper.MOVIES_IMAGE_URL};
int[] to = {R.id.tv_title, R.id.tv_genre, R.id.tv_year, R.id.tv_plot, R.id.tv_rating, R.id.tv_runtime, R.id.img_movie_poster};
adapter = new SimpleCursorAdapter(this.getActivity(), R.layout.movie_list_item, handler.getMovies(), from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if(columnIndex == cursor.getColumnIndex(MoviesDBHelper.MOVIES_IMAGE_URL)) {
DatabaseDownloadImage task = new DatabaseDownloadImage((ImageView) view);
task.execute(cursor.getString(columnIndex));
return true;
}
return false;
}
});
lvMovies.setAdapter(adapter);
}
public class DatabaseDownloadImage extends AsyncTask<String, Integer, Bitmap> {
private ImageView imageView;
public DatabaseDownloadImage(ImageView imageView) {
this.imageView = imageView;
}
#Override
protected Bitmap doInBackground(String... params) {
String address = params[0];
HttpURLConnection connection = null;
Bitmap b = null;
try {
URL url = new URL(address);
connection = (HttpURLConnection) url.openConnection();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return null;
}
else {
b = BitmapFactory.decodeStream(connection.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return b;
}
protected void onPostExecute(Bitmap bitmap) {
if (bitmap == null) {
return;
}
imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 120, 180, false));
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
//Delete all movies from database
case R.id.btn_delete_all_movies:
AlertDialog deleteMovieDialog = new AlertDialog.Builder(this.getActivity()).create();
deleteMovieDialog.setTitle("Delete All Movies?");
deleteMovieDialog.setIcon(R.drawable.ic_delete);
deleteMovieDialog.setButton(DialogInterface.BUTTON_POSITIVE, "No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
deleteMovieDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
handler.deleteAllMovies();
adapter.changeCursor(handler.getMovies());
}
});
deleteMovieDialog.show();
break;
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, final long id) {
AlertDialog deleteMovieDialog = new AlertDialog.Builder(this.getActivity()).create();
deleteMovieDialog.setTitle("Delete Movie?");
deleteMovieDialog.setIcon(R.drawable.ic_delete);
deleteMovieDialog.setButton(DialogInterface.BUTTON_POSITIVE, "No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
deleteMovieDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
handler.deleteMovie(id);
adapter.changeCursor(handler.getMovies());
}
});
deleteMovieDialog.show();
return true;
}
}
All Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly.
http://developer.android.com/intl/es/training/basics/fragments/communicating.html
You can communicate the two fragments with a static variable in the MainActivity that you change in the first fragment and get the content of this variable in the second fragment.
Update:
Create Movie.class, to save all the data of a one movie:
public class Movie() {
String title;
String genre;
int year;
String plot;
int rating;
int runtime;
String img;
public Movie(String title, String genre, int year, String plot, int rating, int runtime, String img) {
this.title=title;
this.genre=genre;
this.year=year;
this.plot=plot;
this.rating=rating;
this.runtime=runtime;
this.img=img;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title=title;
}
//The same for the other variables
}
and in your MainActivity create a static variable of Movie:
public static Movie movie;
In onClick method save the data of the movie:
MainActivity.movie=new Movie(title, genre, year,plot,rating,runtime,img);
And to get the movie in the second fragment:
String title=MainActivity.movie.getTitle();
String genre=MainActivity.movie.getGenre();
...