Fragment of startup with variable name

I was wondering if it is possible to run fragment on a variable name instead of hard-coding the name fragments .

Let me post a sample

Here's how you traditionally run a snippet:

 FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.your_placehodler, new YourFragment()); ft.commit(); 

But say that you are trying to run a fragment without knowing its name, or perhaps it is a fragment . Say like listFragment , or Listview , and you use the array names from fragment . Therefore, you would do something like this:

 @Override public void onListItemClick(ListView l, View v, int position, long id) { private String[] values = new String[] { "frag1", "frag2", "frag3" }; String someFragment = values[position]; String fragName = (someFragment + ".class"); try { FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.your_placehodler, new fragName()); ft.commit(); } catch (Exception e) { //print message } 

I know this is not true, but I feel that, if possible, I can be there. I searched for a while but found nothing.

So my question is: is this possible? If so, how do I implement this? Thanks!

Edit I tried to understand what I thought could work with the Reflections API using this code

 @Override public void onListItemClick(ListView l, View v, int position, long id) { String questions = values[position]; try { Fragment frags = (Fragment) Class.forName("com.example.android." + questions).newInstance(); getFragmentManager() .beginTransaction() .setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out) .replace(R.id.header_fragment_container, frags).commit(); } catch (Exception e) { } } } 

I get a message saying 05-08 04:38:14.124: W/dalvikvm(812): dvmFindClassByName rejecting 'com.android.example.Ovens'

But if in my code I change the line to say Fragment frags = (Fragment) Class.forName("com.android.example." + "Ovens").newInstance();

Works

The "questions" variable is an exact copy of the class name. I do not understand why this will not work. Nothing happens, nothing prints on logcat

Final editing

Got! I missed the marker. Here is the final working code, thanks for the help

 @Override public void onListItemClick(ListView l, View v, int position, long id) { String questions = values[position]; try { Fragment frags = (Fragment) Class.forName("com.android.example." + "" + questions).newInstance(); getFragmentManager() .beginTransaction() .setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out) .replace(R.id.header_fragment_container, frags).commit(); } catch (Exception e) { } } } 
+4
source share
2 answers

One way to achieve this is through reflection APIs.

 Class.forName("com.example.MyFragment").newInstance(); 

This can cause a number of Exceptions, so pay attention to this.

Another way would be to create a simple factory class for your fragments.

 public abstract class MyFragmentFactory { private MyFragmentFactory(){} public static <T extends Fragment> T getFragment(String name){ if("MyFragment".equals(name)){ return new MyFragment(); }else if("whatever".equals(name)){ // ... }else{ throw new RuntimeException("unknown fragment "+ name); } } } 
+5
source

It may be too late to answer, but put here for others. Instead of using

  Fragment frags = (Fragment) Class.forName("com.android.example." + "" + questions).newInstance(); 

using

 Fragment frags = Fragment.instantiate(mContext,"com.android.example." + "" + questions); 

and if you want to pass arguments to the fragment, you can use

 Fragment frags = Fragment.instantiate(mContext,"com.android.example." + "" + questions,bundle); 

where bundle is the bundle that carries your data.

Edit:

What you should prefer over this other:

  • You can send a bundle args to you fragment
  • caching using sClassMap
  • Checks if the initialized class is a fragment or not

Here is the code for the instance method in the snippet

 public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) { try { Class<?> clazz = sClassMap.get(fname); if (clazz == null) { // Class not found in the cache, see if it real, and try to add it clazz = context.getClassLoader().loadClass(fname); if (!Fragment.class.isAssignableFrom(clazz)) { throw new InstantiationException("Trying to instantiate a class " + fname + " that is not a Fragment", new ClassCastException()); } sClassMap.put(fname, clazz); } Fragment f = (Fragment)clazz.newInstance(); if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); f.mArguments = args; } return f; } catch (ClassNotFoundException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (java.lang.InstantiationException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (IllegalAccessException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } } 

where sClassMap is a HashMap

 private static final HashMap<String, Class<?>> sClassMap = new HashMap<String, Class<?>>(); 

obviously you can implement the same function in the above code. Reason not to do this "DRY"

+6
source

Source: https://habr.com/ru/post/1479646/


All Articles