2017-08-17 6 views
2

Est-il possible d'obtenir SomeFragment via une interface? Je ne veux pas utiliser FragmentManager, car dans mon code original MainActivity est un fragment.Comment utiliser Butterknife pour obtenir une référence au fragment xml

public class MainActivity extends AppCompatActivity { 

    @BindView(R.id.some_container) 
    FragmentCallback fragment; 

    public interface FragmentCallback { 
     void test(); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     fragment.test(); 
    } 
} 

public class SomeFragment extends Fragment implements FragmentCallback { 

    public SomeFragment() { 
    } 

    @Nullable 
    @Override 
    public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle 
      savedInstanceState) { 
     View view = inflater.inflate(R.layout.fragment_some, container, false); 
     ButterKnife.bind(this, view); 
     return view; 
    } 

    @Override 
    public void test() { 
     Log.d("" , "it works"); 
    } 
} 

mises en page:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 
    <fragment 
      android:id="@+id/some_container" 
      android:name="com.tamtam.myapplication.SomeFragment" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" /> 
</LinearLayout> 

FATAL: principale EXCEPTION processus: com.tamtam.myapplication, PID: 29138 java.lang.RuntimeException: Impossible de démarrer l'activité ComposantInfo {com. tamtam.myapplication/com.tamtam.myapplication.MainActivity}: java.lang.NullPointerException: Tentative d'invocation de la méthode d'interface 'void com.tamtam.myapplication.MainActivity $ F ragmentCallback.test() » sur une référence d'objet null à android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2665) à android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2726) à androïde. app.ActivityThread.-wrap12 (ActivityThread.java) à android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1477) à android.os.Handler.dispatchMessage (Handler.java:102) à Android. os.Looper.loop (Looper.java:154) at android.app.ActivityThread.main (ActivityThread.java:6119) à java.lang.reflect.Method.invoke (Native Method) à com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:886) à com.android.internal.os.ZygoteInit. principal (ZygoteInit.java:776) causés par: java.lang.NullPointerException: tentative d'invoquer l'interface méthode 'vide com.tamtam.myapplication.MainActivity $ FragmentCallback.test()' sur une référence d'objet null à com.tamtam.myapplication.MainActivity.onCreate (MainActivity.java:21) at android.app.Activity.performCreate (Activity.java:6679) à android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1118) à android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2618) à android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2726) à android.app.ActivityThread.-wrap12 (ActivityThread.java) à android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1477) à android.os.Handler.dispatchMessage (Handler.java:102) à android.os.Looper.loop (Looper.java:154) at android.app.Activi tyThread.main (ActivityThread.java:6119)

Répondre

4

Il est impossible parce

A Fragment est pas un View, @BindView de Butterknife est utilisé pour lier une vue, pas un fragment.

Vous pouvez utiliser FragmentManager.findFragmentById(int id); pour obtenir un fragment, mais si vous vérifiez la mise en œuvre, vous verrez que FragmentManager ne regarde pas dans la hiérarchie View

public Fragment findFragmentById(int id) { 
    if (mAdded != null) { 
     // First look through added fragments. 
     for (int i=mAdded.size()-1; i>=0; i--) { 
      Fragment f = mAdded.get(i); 
      if (f != null && f.mFragmentId == id) { 
       return f; 
      } 
     } 
    } 
    if (mActive != null) { 
     // Now for any known fragment. 
     for (int i=mActive.size()-1; i>=0; i--) { 
      Fragment f = mActive.get(i); 
      if (f != null && f.mFragmentId == id) { 
       return f; 
      } 
     } 
    } 
    return null; 
} 

Si vous voulez faire avec Butterknife

Vous pouvez étendre ButterKnife en ajoutant cette fonctionnalité, ou vous pouvez simplement créer un wrapper autour et rechercher votre propre annotation. Par exemple, vous pouvez créer une annotation personnalisée

@Target(ElementType.FIELD) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface BindFrament { 
    @IdRes int value(); 
} 

créer une enveloppe avec la méthode bind(Activity), appelez ButterKnife.bind(Activity) méthode, puis recherchez votre propre annotation et réglez-le sur le champ d'instance

public class ButterKnifeWrapper { 

    public static void bind(Activity activity){ 
     ButterKnife.bind(activity); 

     Class clazz = activity.getClass(); 
     for(Field field : clazz.getDeclaredFields()){ 
      if(field.isAnnotationPresent(BindFrament.class)){ 
       Class fieldType = field.getType(); 
       if(Fragment.class.isAssignableFrom(fieldType)){ 
        int fragmentId = field.getAnnotation(BindFrament.class).value(); 
        Fragment fragment = activity.getFragmentManager().findFragmentById(fragmentId); 
        try { 
         field.set(activity, fragment); 
        } catch (IllegalAccessException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 
    } 
} 

Dans votre activité vous pouvez alors le faire

public class MyActivity extends AppCompatActivity { 

    @BindFrament(R.id.my_fragment) 
    MyFragment myFragment; 

    @BindView(R.id.my_view) 
    View myView; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.my_activity); 
     ButterKnifeWrapper.bind(this); 
    } 
} 
+0

thnx @lelloman c'est ce que je cherchais. Butterknife devrait avoir cette fonctionnalité par défaut :). –

0

Essayez d'ajouter un fragment d'exécution.

Voici un exemple pour vous.

MainActivity.java

public class MainActivity extends AppCompatActivity { 
    private Fragment1 fragment1; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     if (savedInstanceState == null) { 
      fragment1 = Fragment1.newInstance(); 
     } 
     displayFragmentHome(); 
     // Now you can call your fragment's method 
     fragment1.test(); 
    } 

    private void displayFragmentHome() { 
     FragmentTransaction ft = getFragmentManager().beginTransaction(); 
     if (fragment1.isAdded()) { // if the fragment is already in container 
      ft.show(fragment1); 
     } else { // fragment needs to be added to frame container 
      ft.add(R.id.frame, fragment1, "HOME"); 
     } 
     ft.commit(); 
    } 
} 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <FrameLayout 
     android:layout_width="match_parent" 
     android:id="@+id/frame" 
     android:layout_height="match_parent"></FrameLayout> 
</RelativeLayout> 

Fragment1.java

public class Fragment1 extends Fragment implements FragmentCallBack { 

    private View mView; 

    public static Fragment1 newInstance() { 
     Fragment1 homeFragment = new Fragment1(); 
     return homeFragment; 
    } 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     mView = inflater.inflate(R.layout.fragment_1, container, false); 
     TextView mText = (TextView) mView.findViewById(R.id.text); 
     mText.setText("Welcome.."); 
     return mView; 
    } 

    @Override 
    public void test() { 

    } 
} 

FragmentCallBack.java votre interface

public interface FragmentCallBack { 
    public void test(); 
} 

De cette façon, vous pouvez appeler la méthode d'interface dans votre fragment de votre activité.