Get null FragmentManager/Activity in fragment - android

Scene
I want to update the content of several fragments once I get the response from some HTTP requests.
My Idea
My implementation is something like this:
onCreate of activity, Bind ViewPagerAdapter to it. Then trigger the HTTP request to get data.
Once the request succeeds, update the content in Fragment.
Code
sendRequest. --> adapter.updateFragment(bundle) --> fragment.updateData(bundle);
Activity
protected void onCreate(Bundle savedInstanceState) {
Log.d("DetailedProduct-LifeCycle", "------------onCreate------------");
...
// Set ViewPager
viewPager = findViewById(R.id.view_pager);
adapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
// Send Request
sendRequest();
...
}
public void sendRequest(){
Log.d("DetailedProduct", requestUrl);
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET,
requestUrl,
null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
LinearLayout progressView = findViewById(R.id.progressView);
progressView.setVisibility(View.GONE);
bundle.putString("detail", response.toString());
Log.d("DetailedProduct", "get data:"+response.toString());
Log.d("DetailedProduct", "final Data:" + bundle.toString());
adapter.updateFragment(bundle);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("DetailedProduct", "Cannot get detailed data");
}
});
queue.add(jsonObjectRequest);
}
Adapter
public class ViewPagerAdapter extends FragmentPagerAdapter {
private SellerFragment sellerFragment;
private ShippingFragment shippingFragment;
private ProductSummaryFragment productSummaryFragment;
private FragmentManager fragManager;
public ViewPagerAdapter(FragmentManager fragmentManager){
super(fragmentManager);
sellerFragment = new SellerFragment();
shippingFragment = new ShippingFragment();
productSummaryFragment = new ProductSummaryFragment();
}
#NonNull
#Override
public Fragment getItem(int position) {
// ToDo:
Log.d("ViewPager", position+": ------------getItem----------");
switch (position){
case 0:
if(productSummaryFragment==null){
productSummaryFragment = new ProductSummaryFragment();
}
return productSummaryFragment;
case 1:
if(sellerFragment==null){
sellerFragment = new SellerFragment();
}
return sellerFragment;
case 2:
if(shippingFragment==null){
shippingFragment = new ShippingFragment();
}
return shippingFragment;
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
public void updateFragment(Bundle bundle){
Log.d("ViewPager", "------------updateData----------");
productSummaryFragment.updateData(bundle);
sellerFragment.updateData(bundle);
shippingFragment.updateData(bundle);
}
}
Fragment Sample
public class ShippingFragment extends Fragment {
private TextView shippingSection;
protected JSONObject data;
private AppCompatActivity mActivity;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.shipping_fragment_layout, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
shippingSection = view.findViewById(R.id.shipping_info_section_content);
setData();
}
#Override
public void onAttach(#NonNull Context context) {
Log.d("ShippingFragment", "-----------onAttach----------");
super.onAttach(context);
if(context instanceof AppCompatActivity){
Log.d("ShippingFragment", "---------bind mActivity Success-------");
mActivity = (AppCompatActivity)context;
}
}
#Override
public void onDetach() {
Log.d("ShippingFragment", "-----------onDetach----------");
super.onDetach();
}
// Same for all fragments
public void updateData(Bundle bundle){
Log.d("ShippingFragment", "--------------updateData------------");
setArguments(bundle);
if(mActivity==null){
Log.e("ShippingFragment", "------------activity disappears----------");
}
FragmentManager fragmentManager = mActivity.getSupportFragmentManager();
fragmentManager.beginTransaction().detach(this).attach(this).commit();
}
}
Problem
The log shows that updateData for fragments at position 0,1 works well. but it incurs error for the fragment at position 2.
The difference I found is that the adaptor didn't call getItem for position 2, which means onAttach of shippingFragment doesn't been called. So mActivity does not exist.
Without mActivity, using getFragmentManager in shippingFragment, get this error:
My intuition tells me that the problem must from the work flow of adapter or the fragmentManager transaction. But as a beginner of Android, I have spent all day on them, no clue.
How to fix it? By the way, is there better way to implement my scene?

Try to call viewPager.setOffscreenPageLimit(3) to make sure all 3 fragments are attached to the activity once the activity open.

Related

Retrive data from activity every time oncreateViwe of fragments

Activity
public class GroupesActivity extends BaseActivity {
SelectedBundle selectedBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_groupes);
sectionsPagerAdapter = new GroupPagerAdapter(this, getSupportFragmentManager());
viewPager.setAdapter(sectionsPagerAdapter);
tabs.setupWithViewPager(viewPager);
}
private void getAllGroup() {
// api call retrive data
// send data using interface on response
// set data selectedBundle.onBundleSelect(isVisible,calanderModelList,groupModelList,eventModelList);
}
public void setOnBundleSelected(SelectedBundle selectedBundle) {
this.selectedBundle = selectedBundle;
}
public interface SelectedBundle {
void onBundleSelect(boolean isVisible, List<CalanderModel> calanderModelList, List<GroupModel> groupModelList, List<EventModel> eventModelList);
}
}
Frgment
public class FragmentOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_all_groups_fragments, container, false);
// get data only once on oncreateview
((GroupesActivity) getActivity()).setOnBundleSelected(new GroupesActivity.SelectedBundle() {
#Override
public void onBundleSelect(boolean isVisible, List<CalanderModel> calanderModelListtt, List<GroupModel> groupModelList, List<EventModel> eventModelList) {
Log.e("retrive data","data")
}
});
return root;
}
}
GroupPagerAdapter
public class GroupPagerAdapter extends FragmentPagerAdapter {
#StringRes
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2, R.string.tab_text_3};
private final Context mContext;
public GroupPagerAdapter(Context context, FragmentManager fm) {
super( fm);
this.mContext=context;
}
#NonNull
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new AllGroupsFragments();
case 1:
return new HostFragments();
case 2:
return new GuestFragments();
}
return null;
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getString(TAB_TITLES[position]);
}
#Override
public int getCount() {
return 3;
}
}
problem
i have three fragments in tabview when i swipe this obove fragment
and then come again in this fragmnet that interface not called and i'm
not getting data from activity
How to get that data again from its parent activity, i need to only
retrive that data from activity on each time of fragments oncreateView
Thanks in adavance ;)
Use setMenuVisibility() method in Fragment to fix the issue.
//In fragments
#Override
public void setMenuVisibility(final boolean isVisible) {
super.setMenuVisibility(isVisible);
if (isVisible) {
//visible to user- do ur stuff
((GroupesActivity) getActivity()).setOnBundleSelected(new
GroupesActivity.SelectedBundle() {
#Override
public void onBundleSelect(boolean isVisible, List<CalanderModel>
calanderModelListtt, List<GroupModel> groupModelList, List<EventModel>
eventModelList) {
Log.e("retrive data","data")
}
});
}
}
the following link may help if you face any issues:
How to determine when Fragment becomes visible in ViewPager

Fragment in ViewPager using FragmentPagerAdapter is blank the first time activity is loaded

I'm creating an app with vertical page adapter using FragmentStatePagerAdapter. The big issue i'm facing is, data is not displayed on the textview on first app launch but is displayed on scrolling the page. I believe the fragment view is delaying to create textview because, on my LoadAlbumDataCompleted() function inside Fragmentone.class, i'm able to print the data returned or also output via toast but is not getting populated to the textview.
Kindly help.
MainActivity.class
public class MainActivity extends FragmentActivity implements LoadAalbumsTotalListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new MainActivityVSlideAdapter(this, getSupportFragmentManager(), NUMBER_OF_PAGES);
mPager.setAdapter(mAdapter);
LoadTotalAlbumsNum.BindAlbumsTotalListener(this);
}
#Override
public void OnLoadAlbumsCompleted(String total) {
if(total.trim().equalsIgnoreCase("")){
NUMBER_OF_PAGES=0;
}else{
NUMBER_OF_PAGES=Integer.parseInt(total.trim());
}
mAdapter = new MainActivityVSlideAdapter(this, getSupportFragmentManager(), NUMBER_OF_PAGES);
mPager.setAdapter(mAdapter);
}
}
MainActivityVSlideAdapter.class Adapter
public class MainActivityVSlideAdapter extends FragmentStatePagerAdapter {
static int NUMBER_OF_PAGES;
private Context con;
public MainActivityVSlideAdapter(Context con, FragmentManager fm, int NUMBER_OF_PAGES) {
super(fm);
this.con=con;
this.NUMBER_OF_PAGES=NUMBER_OF_PAGES;
}
#Override
public int getCount() {
return NUMBER_OF_PAGES;
}
#Override
public Fragment getItem(int position) {
return FragmentOne.newInstance(position);
}
}
Fragmentone.class
public class FragmentOne extends Fragment implements LoadAlbumDataListener {
private static final String MY_NUM_KEY = "num";
private int mNum;
private TextView SaloonName;
private TextView location;
// You can modify the parameters to pass in whatever you want
public static FragmentOne newInstance(int num) {
FragmentOne f = new FragmentOne();
Bundle args = new Bundle();
args.putInt(MY_NUM_KEY, num);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//get argument from
mNum = getArguments() != null ? getArguments().getInt(MY_NUM_KEY) : 0;
session=new Session(getActivity());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_one, container, false);
Methods methods=new Methods(getActivity());
// v.setBackgroundColor(mColor);
SaloonName = v.findViewById(R.id.SaloonName);
location=v.findViewById(R.id.location);
new LoadAlbumData(getActivity()).execute(getString(R.string.urlAddress)+"load-album-data.php", String.valueOf(mNum));
LoadAlbumData.BindLoadAlbumDataListener(this);
return v;
}
#Override
public void LoadAlbumDataCompleted(String s) {
JSONArray jsonPicsArray = null;
JSONObject jsonObj;
String BusinessLocation=null;
try {
jsonPicsArray = new JSONArray(s);
businessName = jsonObj.getString("businessName");
BusinessLocation = jsonObj.getString("location");;
}
Toast.makeText(getActivity(), businessName, Toast.LENGTH_LONG).show();
SaloonName.setText(businessName);
location.setText(BusinessLocation);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
From your code, it looks like, you are not setting the LoadAlbumDataListener correctly. Instead of statically setting the listener. Pass reference in constructor of your LoadAlbumData Asynctask
remove this line
LoadAlbumData.BindLoadAlbumDataListener(this);
replace
new LoadAlbumData(getActivity()).execute(getString(R.string.urlAddress)+"load-album-data.php", String.valueOf(mNum));
with
new LoadAlbumData(getActivity(), this).execute(getString(R.string.urlAddress)+"load-album-data.php", String.valueOf(mNum));
Modify your asynctask to have reference of LoadAlbumDataListener
Also as a good practice, never store strong reference of activity or fragment in your asynctask. Use WeakReference.

Fragment in FragmentViewPager does not respond while swiping between Fragment

I've got Drawer Layout that has four Fragments
One of it is Fragment is called Debtors. Debtors has FragmentViewPager that should return FragmentDebtorsForMe or FragmentDebtorsMeToOther.
The way I create CategoryAdapterDebtors in Debtors.class (Debtors extends Fragment)
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewPager viewPager = (ViewPager) view.findViewById(R.id.debtors_viewpager);
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.debtors_tabs);
CategoryAdapterDebtors categoryAdapterDebtors = new CategoryAdapterDebtors
(getChildFragmentManager());
viewPager.setAdapter(categoryAdapterDebtors);
tabLayout.setupWithViewPager(viewPager);
}
CategoryAdapterDebtors that extends FragmentPagerAdapter:
public class CategoryAdapterDebtors extends FragmentPagerAdapter {
public CategoryAdapterDebtors(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if(position==0)
return new FragmentDebtorsForMe();
if(position==1)
return new FragmentDebtorsMeToOther();
return null;
}
#Override
public CharSequence getPageTitle(int position) {
if (position == 0) {
return "For me";
} else if (position == 1) {
return "Me to other";
}
return null;
}
#Override
public int getCount() {
return 2;
}
I will paste one of two fragment that should appear in ViewPager because they have both the same problem and at the beggining those class have the same content.
public class FragmentDebtorsForMe extends Fragment{
private static final String TAG = FragmentDebtorsForMe.class.getSimpleName();
DatabaseClients dbClients;
List<Client> listOfClients;
public FragmentDebtorsForMe() {
Log.i(TAG, "FragmentDebtorsForMe: START");
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate: start");
super.onCreate(savedInstanceState);
listOfClients = getAllClientsFromDatabase();
Log.i(TAG, "onCreate: end");
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Log.i(TAG, "onCreateView: START");
View rootView = inflater.inflate(R.layout.recycler, container, false);
Log.i(TAG, "onCreateView: END");
return rootView;
}
#Override
public void onAttach(Context context) {
Toast.makeText(context, "halo", Toast.LENGTH_SHORT).show();
Log.i(TAG, "onAttach: START");
super.onAttach(context);
}
#Override
public void onDetach() {
Log.i(TAG, "onDetach: START");
super.onDetach();
}
public List<Client> getAllClientsFromDatabase() {
dbClients = new DatabaseClients(getContext());
List<Client> clients = dbClients.getAllClient();
for(Client c: clients)
Log.i(TAG, "getAllClientsFromDatabase: " + c.toString());
return clients;
}
}
Problem is that when I am swiping between Fragments any of my Log.i don't respond.
Other strange things is when on my Navigation Drawer I click debtors then Logs are called both from FragmentDebtorsForMe and FragmentDebtorsMeToOther but only once and no more while swiping between ViewPager.
When I create random view for example for FragmentDebtorsMeToOther it show it view properly(onCreateView work) but Log.i still doesn't work
I don't know what could cause this problem.
Both fragments are created at the same time, that's why you see all logs at once. This is because by default, the ViewPager preloads the next and previous pages. The slowdown you are seeing is caused by the fact that you are accessing your database on the main thread in onCreate(), instead of doing it on a background thread. The main thread must never be blocked because it is responsible for responding to UI events.

How to update recyclerview in the second tab in viewpager from first tab?

One of the problems I am currently facing is that if a user adds something to their timetable, it should be refreshed in the recyclerview in the second tab Current Timetable. However, it never updates and the user has to go back to the main menu, back onto the Timetables activity and then select Current Timetable. I believe it is something to do with my ViewPager and its adapter. I just can't see where I am going wrong and I am sure it is something simple that I am missing. Please could you modify my code such that it will work
Here is my code:
The viewpager class
public class Timetables extends AppCompatActivity{
TabLayout tabLayout;
ViewPager viewPager;
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timetables);
viewPager = (ViewPager) findViewById(R.id.viewPager);
TimetablesAdapter timetablesAdapter = new TimetablesAdapter(getSupportFragmentManager(), Timetables.this);
viewPager.setAdapter(timetablesAdapter);
viewPager.setOffscreenPageLimit(2);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
//viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
//viewPager.setCurrentItem(tab.getPosition());
}
});
}
}
The fragmentpageradapter class:
public class TimestableAdapter extends FragmentPagerAdapter{
String tabNames[] = new String[] {"All timetables", "Current Timetable", "Expired"};
Context context;
public TimestableAdapter(FragmentManager fragmentManager, Context context){
super(fragmentManager);
this.context = context;
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new AllTimetables();
case 1:
return new CurrentTimetables();
case 2:
return new ExpiredTimetables();
default:
return null;
}
}
#Override
public int getCount() {
return tabNames.length;
}
#Override
public CharSequence getPageTitle(int position) {
return tabNames[position];
}
}
This is the CurrentTimetable class:
public class CurrentTimetables extends Fragment {
RecyclerView recyclerView;
static MusicRecyclerAdapter adapter;
RecyclerView.LayoutManager layoutManager;
ArrayList<Timetables> list;
public CurrentTimetables(){
}
#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.currenttimetable, container, false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.timetablerecyclerView);
recyclerView.setHasFixedSize(true);
list = new ArrayList<Timetables>();
adapter = new MusicRecyclerAdapter(list, CurrentTimetables.this);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
tabBackground = new TabBackground(CurrentTimetables.this, list, spinnerItems, adapter, spinnerAdapter);
tabBackground.populateConditionsList();
inputs = new ArrayList<>();
populate();
return rootView;
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
}
#Override
public void onStart() {
super.onStart();
}
public void populate(){
String dbURL = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
RequestQueue requestQueue = Volley.newRequestQueue(fragment.getActivity());
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest
(dbURL, new Response.Listener<JSONArray>(){
#Override
public void onResponse(JSONArray jsonArray) {
if(!list.isEmpty()){
list.clear();
}
try {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
int timetableID = Integer.parseInt(jsonObject.getString("timetableID"));
String timetableName = jsonObject.getString("timetableName");
String subjectName = jsonObject.getString("subjectName");
Timetables timetables = new Timetables(timetableID, timetableName, subjectName);
list.add(timetables);
adapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError volleyError) {
}
}
);
requestQueue.add(jsonArrayRequest);
}
}
Would really mean a lot of someone could help me out
Thanks
There are some changes needed in your code. If you check Fragment's LifeCycle you will understand how it works with Tabular View.
Check out Code I have made from above code.
public class CurrentTimetables extends Fragment {
RecyclerView recyclerView;
static MusicRecyclerAdapter adapter;
RecyclerView.LayoutManager layoutManager;
ArrayList<Timetables> list;
Context context;
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.currenttimetable, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = (RecyclerView) view.findViewById(R.id.timetablerecyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
tabBackground = new TabBackground(CurrentTimetables.this, list, spinnerItems, adapter, spinnerAdapter);
tabBackground.populateConditionsList();
// If you have another Component add here using finViewById() and also you can do
// other process here. I just used setUserVisibleHint because it will execute when
// fragment will be visible to user and it will stop over calling to web service.
/**
* Populate Recyclerview data if setUserVisibleHint do not work.
*/
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
populate();
}
}
public void populate() {
String dbURL = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
RequestQueue requestQueue = Volley.newRequestQueue(context);
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(dbURL, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray jsonArray) {
if (!list.isEmpty()) {
list.clear();
}
try {
list = new ArrayList<Timetables>();
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
int timetableID = Integer.parseInt(jsonObject.getString("timetableID"));
String timetableName = jsonObject.getString("timetableName");
String subjectName = jsonObject.getString("subjectName");
Timetables timetables = new Timetables(timetableID, timetableName, subjectName);
list.add(timetables);
adapter = new MusicRecyclerAdapter(list, context);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
}
});
jsonArrayRequest.setRetryPolicy(new DefaultRetryPolicy(5 * 1000, 1, 1.0F));
jsonArrayRequest.setShouldCache(false);
requestQueue.add(jsonArrayRequest);
}
#Override
public void onResume() {
super.onResume();
populate();
}
}
I might have forgot something from your code and you might have to add it.
You have to create an interface in mainActivity. Reference it in your fragments. Its is the best way to communicate from one fragment to another. Please refer the link below.
http://developer.android.com/training/basics/fragments/communicating.html
Have a look and if any doubts am here to help.

Refreshing a fragment from a DialogFragment

I've been going around in circles trying to do something that seems pretty basic. I have a DialogFragment that accepts a users input, then, on submission, refreshes a ListView in a Fragment that is part of a ViewPager.
I have everything working except the Fragment with the ListView does not refresh itself. It's a little confusing though, because it does refresh the data, but I have to swipe a couple views, then back again to see the updated data.
After doing some research, I'm supposed to use getItemPosition and notifyDataSetChanged on the ViewPager and it should work. The problem is that calling notifyDataSetChanged results in a Recursive entry to executePendingTransactions exception being thrown:
Main Activity
public class Main extends SherlockFragmentActivity implements MyListFragment.OnRefreshAdapterListener, DialogConfirmation.OnRefreshKeywordsListener //Updated Code
{
private static List<Fragment> fragments;
#Override
public void onCreate(final Bundle icicle)
{
setContentView(R.layout.main);
}
#Override
public void onResume()
{
mViewPager = (ViewPager)findViewById(R.id.viewpager);
fragments = new ArrayList<Fragment>();
fragments.add(new MyListFragment()); //fragment with the ListView
fragments.add(MyDetailFragment.newInstance(0));
fragments.add(MyDetailFragment.newInstance(1));
fragments.add(MyDetailFragment.newInstance(2));
mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mMyFragmentPagerAdapter);
}
private static class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
return fragments.get(index);
}
#Override
public int getCount() {
return 4;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
#Override
public void onRefreshAdapterListener() {
this.mMyFragmentPagerAdapter.notifyDataSetChanged();
}
//Updated Code
#Override
public void onRefreshTextListener() {
MyListFragment tf = (MyListFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentText);
if (tf == null)
tf = (MyListFragment)this.fragments.get(0);
tf.RefreshText();
}
}
ListFragment
public class MyListFragment extends SherlockListFragment
{
OnRefreshAdapterListener mRefreshAdapter;
#Override
public void onActivityCreated(Bundle savedState) {
adapter = new CustomAdapter();
/*code to add items to adapter */
this.setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (getArguments() != null && getArguments().getString("text").length() > 0)
{
SaveText(getArguments().getString("text"));
this.mRefreshAdapter.onRefreshAdapterListener(); //this line causes a "java.lang.IllegalStateException: Recursive entry to executePendingTransactions" exception
}
return inflater.inflate(R.layout.listing, container, false);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mRefreshAdapter = (OnRefreshAdapterListener)activity;
}
public interface OnRefreshAdapterListener {
public void onRefreshAdapterListener();
}
#Override
public void onDialogTextAdd(final String text) {
}
}
DialogFragment
public class DialogTextAdd extends DialogFragment implements OnEditorActionListener {
private EditText mText;
OnRefreshTextListener mTextKeywords; //Updated Code
public interface DialogTextAddListener {
void onDialogTextAdd(final String inputText);
}
public DialogTextAdd() {
// Empty constructor required for DialogFragment
}
//Updated Code
#Override
public void onAttach(Activity act) {
super.onAttach(act);
mTextKeywords = (OnRefreshTextListener)act;
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.dialog_edit, container);
mText = (EditText)view.findViewById(R.id.text_add);
getDialog().setTitle("Add Text");
// Show soft keyboard automatically
mText.requestFocus();
getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
mText.setOnEditorActionListener(this);
return view;
}
#Override
public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
if (EditorInfo.IME_ACTION_DONE == actionId) {
MyListFragment mf = new MyListFragment();
Bundle args = new Bundle();
args.putString("text", mText.getText().toString());
mf.setArguments(args);
//this seems to be intefering with the notifyDataSetChanged in the listing fragment
getActivity().getSupportFragmentManager().beginTransaction().add(mf, "my_fragment").commit();
mTextKeywords.onRefreshTextListener(); //Updated Code
this.dismiss();
return true;
}
return false;
}
}
I have everything working except the Fragment with the ListView does
not refresh itself.
There is no point on creating and adding to the FragmentActivity a new instance of MyListFragment. From your code it appears that you store the fragments that you use in a list so you have references to them(also, just out of curiosity, did you setup the fragments in portrait, did a rotation of the phone and retried to use the DialogFragment?). Having references to those fragment means you could always get them from the list and use them to call a refresh/update method.

Categories

Resources