This is my 1st question so i will try to b as precise as possible. I am trying the create an application using Fragment Activity, Fragment List and View Pager. When the activity loads by default the fragment list should be shown to the left and view pager is shown to the right (the detail view). When i click one of the fragment list buttons i want to load a webview in the detail view (right side).
I have implemented the Fragment Activity with Fragment List. Now how to add View Pager to this so that it shows up when the application loads up ..
public class MainActivity extends FragmentActivity implements McDonaldsListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
McDonaldsFragment countries
=(McDonaldsFragment)getSupportFragmentManager()
.findFragmentById(R.id.countries);
countries.setCountryListener(this);
Fragment f=getSupportFragmentManager().findFragmentById(R.id.details);
countries.enablePersistentSelection();
}
#Override
public void onCountrySelected(McDonalds c) {
String url=getString(c.url);
((DetailsFragment)getSupportFragmentManager()
.findFragmentById(R.id.details))
.loadUrl(url);
}
}
There are other supporting classes which if there is need i will post it.
Hope some one can suggest me some solutions.
Edit:
This is what i tried to implement but dosent work....Gives Instantiation Exception :(
public class ViewPagerExample extends android.support.v4.app.FragmentActivity implements McDonaldsListener {
private MyAdapter mAdapter;
private ViewPager mPager;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
McDonaldsFragment mc
=(McDonaldsFragment)getSupportFragmentManager()
.findFragmentById(R.id.countries);
mc.setCountryListener(this);
Fragment f=getSupportFragmentManager().findFragmentById(R.id.details);
mc.enablePersistentSelection();
}
public void onCountrySelected(McDonalds c) {
String url=getString(c.url);
((DetailsFragment)getSupportFragmentManager()
.findFragmentById(R.id.details))
.loadUrl(url);
}
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 3;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new DetailFragment();
case 1:
return new ImageFragment(R.drawable.ic_launcher);
case 2:
return new ImageFragment(R.drawable.ic_launcher);
default:
return null;
}
}
}
}
lets try this peter kuterna view pager
http://blog.peterkuterna.net/2011/09/viewpager-meets-swipey-tabs.html
Related
I have got aplication with three screens(3 fragments and viewPager), and now I want to send for example String from Activity to FragmentA but I don't know how.
This is my Activity class with pager Adapter
public class MainActivity extends FragmentActivity {
ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager= (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
}
}
class MyAdapter extends FragmentPagerAdapter{
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int arg0) {
Fragment fragment=null;
if(arg0==0){
fragment=new FragmentA();
}
if(arg0==1){
fragment=new FragmentB();
}
if(arg0==2){
fragment=new FragmentC();
}
return fragment;
}
#Override
public int getCount() {
return 3;
}
You can use the EventBus library or write something similar yourself, but the best option is to learn the correct and accepted methods of communication between components.
If you want to pass the data (String in your case) before the ViewPager initialized you can pass it via argumnents, here you can find a good example.
Im having an issue that only appears after several hours of inactivity, I researched it ive tried various ways of fixing it to no avail. The issue is after my app has been dormant for several hours the references for my fragments are null, however; they still exist in the frag manager. I use the references to pull the tag, or id by findfragmentby...() so I can call specific methods within them for updating themselves and what not. The fragments are dynamic and have a UI. I have several activities and a service that are called on by the main activity. I can close the app and resume, call activities, pull info from the service, close, use the back button, all without an issue. To give you an idea of how the app is structured...
public class appClass extends Application {
public Fragment fragmentA;
public Fragment fragmentB;
public Fragment fragmentC;
#Override
public void onCreate() {
super.onCreate();
new fragmentTemplate();
fragemntA = fragmentTemplate.newInstance(getDbName(), usefuldata, "A List");
new fragmentTemplate();
fragemntB = fragmentTemplate.newInstance(getDbName(), usefuldata, "B list");
new fragmentTemplate();
fragemntC = fragmentTemplate.newInstance(getDbName(), usefuldata, "C list");
}
}
Moving on to activity where fragments are used in a viewager...
public class mainActivity extends AppCompatActivity implements ...listeners{
appClass myAppClass;
FragmentManager FragMgr;
ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myAppClass = (appClass) getApplication();
setTheme(myAppClass.getAppTheme());
setContentView(R.layout.activity_my_layout);
//toolbar actionbar stuff
FragMgr = getSupportFragmentManager();
viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new ViewPagerAdapter(FragMgr));
//tab setup
}
//inner class pager adapter is here
}
This is my pager adapter
class ViewPagerAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener{
Fragment fragment;
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
if (myAppClass.fragmentA != null) {
fragment = myAppClass.fragemntA ;
}
break;
case 1:
if (myAppClass.fragmentB != null) {
fragment = myAppClass.fragmentB ;
}
break;
case 2:
if (myAppClass.fragmentC != null) {
fragment = myAppClass.fragmentC ;
}
break;
}
return fragment;
}
#Override
public int getCount() {
return 3;
}
}
I have a FAB and its listener looks like this
#Override
public void onClick(View v) {
Fraggment fragment;
int i = viewPager.getCurrentItem();
if (v.getId() == floatingActionButton.getId()) {
switch (i) {
case 0:
fragment= (Fragment) FragMgr.findFragmentByTag(myAppClass.fragmentA.getTag());
fragment.addItem(fragment.getSomeString());
break;
case 1:
fragment= (Fragment) FragMgr.findFragmentByTag(myAppClass.fragmentB.getTag());
fragment.addItem(fragment.getSomeString());
break;
case 2:
fragment= (Fragment) FragMgr.findFragmentByTag(myAppClass.fragmentC.getTag());
fragment.addItem(fragment.getSomeString());
break;
}
}
}
code for a fragment
public class fragmentTemplate extends Fragment implements RecyclerAdapter.aListener {
private appClass myAppclassReference;
private RecyclerView recyclerView;
private View view;
private FragmentTitle;
public static fragmentTemplate newInstance(String a, String b, String c) {
Bundle args = new Bundle();
args.putString(KEY_A, a);
args.putString(KEY_B, b);
args.putString(KEY_C, c);
fragmentTemplate fragment = new fragmentTemplate();
fragment.setArguments(args);
return fragment;
}
public String getFragmentTitle() {
return fragmentTitle;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, final Bundle savedInstanceState) {
view = inflater.inflate(R.layout.list, container, false);
myAppclassReference= ((appClass) getActivity().getApplication());
recyclerView = (RecyclerView) view.findViewById(R.id.listView);
//get list is a local function that loads a list from a db source
RecyclerAdapter recycler = new RecyclerAdapter(getActivity(), getList());
recycler.setListener(this);
recyclerView.setAdapter(recycler);
recyclerView.setLayoutManager(newLearLayoutManager(getActivity()));
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {}};
return view;
}
}
When things go wonky the app does not crash right away, the tabs still scroll, the viewpager still scrolls, but it is empty, its not until I hit the FAB do I get a nullpointerexception, trying to invoke a method on a nullpointer reference within the onClick Listener does it actually crash.
This is happening because you are messing up with the way that the Android Framework handles Fragments for you. When the ViewPagerAdapter gets Fragments from you in getItem(int), it's using the FragmentManager that you gave it to attach the Fragments. Once the Activity is killed because of low memory, the FragmentManager will automatically create new instances of your Fragments. At this point there are two copies of the fragments, the ones the FragmentManager created and the ones you recreated in your appClass.
You should never keep references to your Fragments. The FragmentManager is free to destroy them and create new ones. If you need to communicate between the Activity and the Fragments in the ViewPager, you can either make the Fragment ask its Activity for commands, use an Event Bus, or explore the sketchy solutions here.
This is the situation. I have an activity with 5 tabs (5 fragments). One of the fragments uses a RecyclerView to show a list of posts (like a forum). When users tap on an item menu, I need to implement the possibility of send a new post and update the list. I have no problems sending the new post to my DB and managing the response, but I don’t know how to, from the activity, tell the fragment to tell de adapter to update the list. I hope I’m explaining myself (English is not my first language).
This is my code so far.
The activity:
public class UsuarioActivity extends AppCompatActivity {
public ViewPager mPager;
public SlidingTabLayout mTabs;
...
protected void onCreate (Bundle savedInstanceState) {
mPager = (ViewPager) findViewById(R.id.pagerUsuario);
mTabs = (SlidingTabLayout) findViewById(R.id.tabsUsuario);
...
mPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
mTabs.setCustomTabView(R.layout.custom_tab_view, R.id.tabText);
mTabs.setDistributeEvenly(true);
mTabs.setBackgroundColor(getResources().getColor(R.color.white));
mTabs.setViewPager(mPager);
}
class MyPagerAdapter extends FragmentStatePagerAdapter {
FragmentManager fragmentManager;
public MyPagerAdapter (FragmentManager fm) {
super(fm);
fragmentManager = fm;
}
#Override
public Fragment getItem (int position) {
Fragment fragment = null;
switch (position) {
case TAB_INFO:
fragment = FragmentUserInfo.getInstance(usuario);
break;
case TAB_COM:
fragment = FragmentUserComment.getInstance(usuario);
break;
case TAB_SEG:
fragment = FragmentUserSeg.getInstance(usuario);
break;
case TAB_IM:
fragment = FragmentUserImages.getInstance(usuario);
break;
case TAB_FILES:
fragment = FragmentUserFiles.getInstance(usuario);
break;
}
return fragment;
}
#Override
public CharSequence getPageTitle (int position) { ... }
#Override
public int getCount () { return TAB_COUNT; }
}
}
The fragment:
...
import android.support.v4.app.Fragment;
...
public class FragmentUserComment extends Fragment {
private RecyclerView recyclerView;
private RVIndexCommetAdapter indexCommetAdapter;
private static final String KEY_USUARIO = "KEY_USUARIO";
public static FragmentUserComment getInstance (Usuario usuario) {
FragmentUserComment fragmentUserComment = new FragmentUserComment();
Bundle args = new Bundle();
args.putLong(KEY_USUARIO, idusuario);
fragmentUserComment.setArguments(args);
return fragmentUserComment;
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
usuario = getArguments().getLong(KEY_USUARIO);
View layout = inflater.inflate(R.layout.fragment_user_comment, container, false);
recyclerView = (RecyclerView) layout.findViewById(R.id.recViewUsuariosComment);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
indexCommetAdapter = new RVIndexCommetAdapter(getContext());
indexCommetAdapter.setListaComentarios(usuario.list);
recyclerView.setAdapter(indexCommetAdapter);
}
I think it’s not necessary to copy here the adapter class since my main problem is how to send the new post data from the activity to the fragment.
PS: In case anyone suggests this to me, I know I could send the new post to my DB and managing the response directly in the fragment, not in the activity. In fact, that was my first try, but onOptionsItemSelected doesn’t catch the event of tapping the item menu and I lost enough time trying to solve it (reading lots of questions here included), so I tried this new approach.
Thanks in advance.
To refresh the list from Activity you should make your Adapter static and call from your Activity notifyDataSetChanged(), it probably look like this
FragmentUserComment.mAdapter.notifyDataSetChanged();
To send data from Activity to Fragment you could make class with static variables and write them datas in your Activity and read them in Fragment. It's rather not the most professional method, but it works and it's very easy to implement.
create the method in the FragmentUserComment,look like this:
public void updateList(datas){
mAdapter.setdatas(datas);
mAdapter.notifyDataSetChanged();
}
you can call updateList() in activity when you refresh the list
((FragmentUserComment)fragment).updateList(datas);
I understand that this is quite a common issue, and I have referred to many different other questions but I still can't get this to work.
My activity implements a view pager with two tabs and in each tab is a listview. I have a adapter for my view pager which links the two fragments and in each fragment, a adapter to link the data to the listview.
In my activity menu, I have a menu which creates an edittext in an alertdialog for me to input new fields into one of the listview in one of the fragment.
My activity (contains a viewpager)
protected void onCreate(Bundle savedInstanceState)
{
...
subAdapter = new SubAdapter(getSupportFragmentManager(), data);
((ViewPager) findViewById(R.id.viewPager)).setAdapter(subGroupAdapter);
}
My viewpager adapter
public class SubAdapter extends FragmentPagerAdapter
{
public SubGroupAdapter(FragmentManager fm, data data)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
Bundle bundle = new Bundle();
bundle.putString("data", data);
switch (position)
{
case 0:
Fragment1 frag1 = new Fragment1();
frag1.setArguments(bundle);
return frag1;
case 1:
Fragment2 frag2 = new Fragment2();
frag2.setArguments(bundle);
return frag2;
}
return null;
}//some other methods below
Fragment1 / Fragment2 (both fragments have a listview)
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
frag1Adapter = new frag1Adapter(this, data);
((ListView) getView().findViewById(R.id.listView)).setAdapter(frag1Adapter);
}
Custom listview adapter for both listviews in both fragments
public class ExpenseAdapter extends BaseAdapter implements OnClickListener
{ ... }
As I mentioned earlier, I can input a new entry into either listview from the activity action bar button. However, the listview does not get updated and I can't reference the listview adapter to call notifydatasetchanged() from the activity.
What is the best way I can proceed from here onwards? thank you so much!
I have tried exploring using interfaces, tags but can't get it to work currently.
What you should do is create a public method for your Fragment1 and Fragment2 like so:
define in your Activity:
Fragment1 frag1;
Fragment2 frag2;
then your ViewPager:
public class SubAdapter extends FragmentPagerAdapter
{
public SubGroupAdapter(FragmentManager fm, data data)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
Bundle bundle = new Bundle();
bundle.putString("data", data);
switch (position)
{
case 0:
frag1 = new Fragment1();
frag1.setArguments(bundle);
return frag1;
case 1:
frag2 = new Fragment2();
frag2.setArguments(bundle);
return frag2;
}
return null;
}
}
Put this method in Fragment1.java :
public void updateFragment1ListView(){
if(adapter != null){
adapter.notifyDataSetChanged();
}
}
and from your activity call:
if(frag1 != null){
frag1.updateFragment1ListView();
}
obviously change the names for your adapter if its not called adapter...
Just do the same for Fragment2.java as well
I would recommend creating an interface. Here's an Example:
public interface UpdateListFragmentInterface {
void updateList();
}
Then in the Activity, add the delegate as a property:
UpdateListFragmentInterface yourDelegate;
Wherever you create the Fragment within the Activity, assign the Fragment as the delegate:
// Set up and create your fragment.
(if yourFragment instanceof UpdateListFragmentInterface) {
yourDelegate = yourFragment;
}
Then in the Fragment, implement the interface:
public class YourListFragment extends android.support.v4.app.ListFragment implements UpdateListFragmentInterface {
// Constructors and other methods for the ListFragment up here.
// Override the interface method
public void updateList() {
//Update the list here.
}
}
Then finally, from within your Activity, when you need to update the list, simply call the delegate:
yourDelegate.updateList();
EDIT:
Sorry, I think you actually need to create a public method in your activity that is something like:
public void setUpdateListFragmentDelegate(UpdateListFragmentDelegate delegate) {
this.delegate = delegate
}
Then in the on attach of the List Fragment you will assign it there:
if (context instance of YourActivity) {
((YourActivity)context.setUpdateListFragmentDelegate(this);
}
I got a simple FragmentPageAdapter in my Activity and it works fine. Now I would like to extend from a BaseActivity because I implemented a navigation drawer inside of the BaseActivity. Therefore I cannot extend of the FragmentActivity Class and I tried to declare a FragmentActivity object but I always get the error java.lang.IllegalStateException: Activity has been destroyed. How can I handle this problem?
public class MainActivity extends BaseActivity {
FragmentPagerAdapter adapterViewPager;
FragmentActivity fa;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentActivity fa = new FragmentActivity();
adapterViewPager = new MyPagerAdapter(fa.getSupportFragmentManager());
ViewPager pager = (ViewPager) findViewById(R.id.viewPager);
pager.setAdapter(adapterViewPager);
pager.setAdapter(new MyPagerAdapter(fa.getSupportFragmentManager()));
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: // Fragment # 0 - This will show FirstFragment
return SlideFragment.newInstance(0, "Page # 1");
case 1: // Fragment # 0 - This will show FirstFragment different title
return SlideFragment.newInstance(1, "Page # 2");
case 2: // Fragment # 1 - This will show SecondFragment
return SlideFragment.newInstance(2, "Page # 3");
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
}
#Override
protected int getLayoutResourceId() {
// TODO Auto-generated method stub
return R.layout.activity_main;
}
}
You don't need to use a FragmentActivity object in MainActivity. Just extend FragmentActivity in your BaseActivity class.
Never create manually activity objects. You are always inside some activity class(properly instantiated).
What you need is your BaseActivity to extends FragmentActivity.