2017-08-17 38 views
2

是否可以通過接口獲取SomeFragment?我不想使用FragmentManager,因爲在我的原始代碼中MainActivity是一個片段。如何使用Butterknife獲取對片段的引用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"); 
    } 
} 

佈局:

<?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> 

致命異常:主 工藝:com.tamtam.myapplication,PID:29138 了java.lang.RuntimeException:無法啓動活動 ComponentInfo {融爲一體。 tamtam.myapplication/com.tamtam.myapplication.MainActivity}: java.lang.NullPointerException:試圖調用接口方法 'void com.tamtam.myapplication.MainActivity $ F ragmentCallback.test()」 上在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 在機器人空對象引用 。 app.ActivityThread.-wrap12(ActivityThread.java) 在 android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1477) 在android.os.Handler.dispatchMessage(Handler.java:102) 的機器人。 os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit。主(ZygoteInit.java:776) 所致:顯示java.lang.NullPointerException:嘗試在 調用接口 方法 '無效 com.tamtam.myapplication.MainActivity $ FragmentCallback.test()' 上的 空對象引用 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) at android.os.Looper.loop(Looper.java:154) at android.app.Activi tyThread.main(ActivityThread.java:6119)

回答

4

這不是可行的,因爲

Fragment不是View,Butterknife的@BindView被用於結合視圖,而不是一個片段。

您可以使用FragmentManager.findFragmentById(int id);獲得一個片段,但是如果你檢查落實,你會看到FragmentManager不會在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; 
} 

看,如果你想與ButterKnife做到這一點

您可以通過添加此功能來擴展ButterKnife,或者您可以創建一個包裝並查找自己的註釋。例如,您可以創建一個自定義的註釋

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

創建一個包裝與bind(Activity)方法,調用ButterKnife.bind(Activity)方法,然後尋找自己的註釋並將其設置爲實例字段

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(); 
        } 
       } 
      } 
     } 
    } 
} 

在你的活動你可以這樣做

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這就是我正在尋找的。 Butterknife默認應該有這個功能:)。 –

0

嘗試添加片段運行時。

下面是一個例子給你。

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你的界面

public interface FragmentCallBack { 
    public void test(); 
} 

這樣你可以從你的活動調用接口的方法在你的片段。