I am new in android i am stuck while working with fragment any help in this is really appreciated.I am working with fragment for tablet. There are two fragment suppose FragmentA(Left side fragment) and FragmentB(Right side Fragment) both are list fragment, FragmentB change according to FragmentA. There is another fragment, FragmentC which inflates on clicking the item on List of FragmentB. Now after inflating the FragmentC when I click on the FragmentA my app Crashes. There is an error in logcat showing FragmentC can't cast into FragmentB. I am trying to solve this problem from last 10 hours but no result came out.
This is my MainActivity class
public class MainActivity extends FragmentActivity implements FragmentA.Communicator{
FragmentManager manager;
FragmentB frag2;
FragmentA frag1;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frag);
manager=getSupportFragmentManager();
FragmentA frag1=(FragmentA ) manager.findFragmentById(R.id.fragment1);
frag1.setCommunicator(this);
}
#SuppressLint("NewApi")
#Override
public void respond(int index) {
// TODO Auto-generated method stub
frag2= (FragmentB) manager.findFragmentById(R.id.fragment2);
frag2.changeData(index);
}
}
This is my FragmentA class
public class FragmentA extends Fragment implements OnItemClickListener{
Communicator comm;
ListView list;
String[] items={"Beverages","Food"};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.menu_list,container, false);
list=(ListView) view.findViewById(R.id.listView1);
ArrayAdapter<String> adapter= new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,items);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
return view;
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int i, long arg3) {
// TODO Auto-generated method stub
comm.respond(i);
}
public void setCommunicator(Communicator communicator){
this.comm=communicator;
}
public interface Communicator{
public void respond(int index);
}
}
This is my FragmentB class
public class FragmentB extends Fragment implements OnItemClickListener {
ListView listmenu;
String[] listItem1={"item1","item2","item3","item4","item5"};
String[] listItem2={"itemA","itemB","itemC","itemD","itemE"};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.menu, container, false);
listmenu=(ListView) view.findViewById(R.id.listView_menu);
return view;
}
public void changeData(int index){
if(index==0){
ArrayAdapter<String> adapter=new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,listItem1);
listmenu.setAdapter(adapter);
}
}
if(index==1){
ArrayAdapter<String> adapter=new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,listItem2);
listmenu.setAdapter(adapter);
}
listmenu.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
// TODO Auto-generated method stub
//Intent intent = null;
switch(position){
case 0: FragmentManager manager=getFragmentManager();
Fragment frag1=new FragmentC();
FragmentTransaction ft=manager.beginTransaction();
ft.replace(R.id.fragment2, frag1,"A");
ft.addToBackStack("A");
ft.commit();
break;
}
}
}
I think you need check which of the 2 fragments is 'alive'. If Fragment B is active try to close it first and re-open Fragment A. Then you can continue the process.
Related
I am working on an android application. I am loading some view inside a fragment in an activity. The First Fragment is having Gridview/ListView in this. I want to load another Fragment in the same activity when any Item of Listview/Gridview will be clicked, without restarting the activity.
How can I do this?
Here is an example. It not an exact answer, its just for a hint.
Fragment class may be look like this:
public class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Append the clicked item's row ID with the content provider Uri
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
// Send the event and Uri to the host activity
mListener.onArticleSelected(position);
}
}
And the activity class will be like below:
public static class DetailsActivity extends Activity implements FragmentA.OnArticleSelectedListener{
#Override
public void onArticleSelected(int position){
// your implementation ...
}
}
Fragment Code:
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {
YourFragment yf= new YourFragment ();
((HomeActivity) mActivity).replceFrament(groupControlFragment);
}
});
MainActivity Code:
public void replceFrament(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment,tag).addToBackStack("back").commit();
}
Inside your fragment which has the listview/gridview.
Fragment[] fragment=new Fragment{new MyFragment1(), new MyFragment2(), new MyFragment3()};
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState){
View view=inflater.inflate(R.layout.mylayout, container, false);
ListView listView=(ListView)view.findViewById(R.id.list_id);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
replaceFragment(fragment[i]);
}
});
return view;
}
public void replaceFragment(Fragment fragment){
FragmentManager fragmentManager=getFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerLayout,fragment);
fragmentTransaction.addToBackStack(null); //Optional
fragmentTransaction.commit();
}
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.
MainActivity.java
public class MainActivity extends SherlockFragmentActivity {
static MyListfragment mf;
ViewPager mpager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mf = new MyListfragment();
ft.add(android.R.id.content,mf).commit();
}}
MyListfragment.java
public class MyListfragment extends SherlockListFragment {
MyDisplayfragment tempFrag;
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Connector.selection = position;
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
if(position==0)
{
tempFrag=new MyDisplayfragment();
tempFrag.setLayout(R.layout.law);
subFragmentAdapter mAdapter = new subFragmentAdapter(getChildFragmentManager());
tempFrag.setViewPagerAdapter(mAdapter);
}
ft.replace(android.R.id.content,tempFrag);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1;
setListAdapter(new ArrayAdapter<String>(getActivity(),
layout, Connector.list));
}}
MyDisplayfragment.java
public class MyDisplayfragment extends SherlockFragment {
int resource;
FragmentPagerAdapter mAdapter;
ViewPager v;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
if(Connector.selection==-1)
resource=R.layout.displayfragment;
return inflater.inflate(resource, container, false);
}
public void setViewPagerAdapter(FragmentPagerAdapter x)
{
mAdapter=x;
}
public void setLayout(int layout)
{
resource=layout;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
ViewPager pager=(ViewPager) view.findViewById(R.id.mpager);
pager.setAdapter(mAdapter);
}}
subFragment.java
public final class subFragment extends SherlockFragment {
private int layout;
public static subFragment newInstance(int content) {
subFragment fragment = new subFragment();
fragment.layout=content;
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(layout,container,false);
}}
subFragmentAdapter.java
public class subFragmentAdapter extends FragmentPagerAdapter{
int[] LAYOUT={R.layout.cccc,R.layout.aaaa,R.layout.bbb};
private int mCount;
public subFragmentAdapter(FragmentManager fm) {
super(fm);
mCount = LAYOUT.length;
}
#Override
public Fragment getItem(int position) {
return subFragment.newInstance(LAYOUT[position]);
}
#Override
public int getCount() {
return mCount;
}
}
Connector.java
public class Connector {
static int selection = -1;
static String list[] = { "Law" };}
In the above project
1)MyListfragment.java is used for navigation
2)MyDisplayfragment.java is used to display according to selection made in MyListFragment
3)Connector.java is used to communicate between the above two fragments
4)subFragment.java is used to populate Viewpager with Fragments
5)subFragmentAdapter.java is th adapter for Viewpager
When i run this project the viewpager seems to be blank and doesnot show any of the child fragments and after debugging i saw that onCreateView() method of subFragment.java is not called.
My question is why the onCreateView() method is not being called
Please refer to Luksprog's comment for the answer.
Originally, I have 2 Activities. A call B activities. Now I changed the A class extends SherlockFragmentActivity and B class extends SherlockFragment.
I tried to changed these in A class:
private class MyTabListener implements ActionBar.TabListener {
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (tab.getPosition()==1) {
B frag = new B();
ft.replace(android.R.id.content, frag);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
//=============================
In B class:
public class Br extends SherlockFragment{
/* Called when the activity is first created */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.promotionslist_tableview);
//get our listview
ListView myListView = (ListView) findViewById(R.id.myListView_promotionslist_table);
//==============================
BUT ERROR.
1. onCreate
2. findViewById..
What i am wrong ?
please give me some hints. Thanks.
I can now display the B fragement but the listview overlap on the main listview..?
Why ?
public class B extends SherlockFragment{
View view;
/* Called when the activity is first created */
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//setContentView(R.layout.promotionslist_tableview);
//get our listview
ListView myListView = (ListView) view.findViewById(R.id.myListView_promotionslist_table);
.
.
.
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.promotionslist_tableview, container, false);
return view;
}
You have to use the onCreateView() method in fragments:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout, null);
return view;
}
There you can inflate a View and call findViewById like this:
view.findViewById(...);
I've got a ListFragment which provides a ContextMenu for its elements. When I put this fragment in an xml-layout everything works fine but when I add this ListFragment programmatically via the FragmentManager then this works only until the first screen-rotation. After rotating the screen I can see in the debugger that Android restores the old ListFragment AND creates a new one due to
CustomListFragment fragment = new CustomListFragment();
fragmentTransaction.add(R.id.customFragmentContainer, fragment);
where a new ListFragment gets created. When I long-press an item to open the ContextMenu, then the onCreateContextMenu method of the new ListFragment gets called and the result is passed to the onContextItemSelected method of the old ListFragment.
I think it gets clearer when I post a bit of code:
Here's my ListFragment:
public class CustomListFragment extends ListFragment {
private LayoutInflater layoutInflater;
private OnSelectedListener<String> selectionListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
layoutInflater = inflater;
return inflater.inflate(R.layout.list_fragment_layout, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(new CustomListAdapter());
registerForContextMenu(getListView());
}
public void setOnSelectedListener(OnSelectedListener<String> listener) {
selectionListener = listener;
}
private static final String item0 = "item0";
private static final String item1 = "item1";
#Override
public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.add(0, 0, 0, item0);
menu.add(0, 1, 0, item1);
}
#Override
public boolean onContextItemSelected(MenuItem menuItem) {
String selection;
if (menuItem.getItemId()==0)
selection = item0;
else
selection = item1;
if (selectionListener!=null)
selectionListener.onSelected(selection);
return true;
}
private class CustomListAdapter extends BaseAdapter {
private List<String> elemente = new ArrayList<String>();
public CustomListAdapter() {
elemente.add("one");
elemente.add("two");
elemente.add("three");
}
#Override
public int getCount() {
return elemente.size();
}
#Override
public Object getItem(int position) {
return elemente.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null)
convertView = layoutInflater.inflate(R.layout.element, null);
TextView tv = (TextView)convertView;
tv.setText(elemente.get(position));
return tv;
}
}
}
With this Activity it works fine:
public class CustomFragmentActivity extends FragmentActivity implements OnSelectedListener<String> {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
FragmentManager fragmentManager = getSupportFragmentManager();
CustomListFragment fragment = (CustomListFragment)fragmentManager.findFragmentById(R.id.customFragment);
fragment.setOnSelectedListener(this);
}
#Override
public void onSelected(String selection) {
Toast.makeText(this, selection, Toast.LENGTH_LONG).show();
}
}
But with this Activity it only works until the first screen-rotation:
public class CustomFragmentContainerActivity extends FragmentActivity implements OnSelectedListener<String> {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_container_layout);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
CustomListFragment fragment = new CustomListFragment();
fragmentTransaction.add(R.id.customFragmentContainer, fragment);
fragmentTransaction.commit();
fragment.setOnSelectedListener(this);
}
#Override
public void onSelected(String selection) {
Toast.makeText(this, selection, Toast.LENGTH_LONG).show();
}
}
The OnSelectedListener is only an inteface which provides one single public method. After a screen-rotation the result (the selected item) is passed to the old ListFragment. But this old ListFragment is recreated by the Android system and the selectionListener is null, so nothing happens. The interface looks like this:
public interface OnSelectedListener<V> {
public void onSelected(V selection);
}
And finally, maybe I should mention that I'm using the v4 support library.
Ok, the problem is, that there's a memory leak in the support library and the onContextItemSelected()-method of the old fragments gets called. And as I return true, the newer fragments don't get this method call.