如何使用 Butterknife 获取对片段的引用 xml
How to use Butterknife to get a reference to the fragment xml
是否可以通过接口获取SomeFragment?我不想使用 FragmentManager,因为在我的原始代码中 MainActivity 是一个片段。
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>
FATAL EXCEPTION: main
Process: com.tamtam.myapplication, PID: 29138
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.tamtam.myapplication/com.tamtam.myapplication.MainActivity}:
java.lang.NullPointerException: Attempt to invoke interface method
'void com.tamtam.myapplication.MainActivity$FragmentCallback.test()'
on a null object reference
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.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.main(ZygoteInit.java:776)
Caused by: java.lang.NullPointerException: Attempt to invoke interface
method 'void
com.tamtam.myapplication.MainActivity$FragmentCallback.test()' on a
null object reference
at
com.tamtam.myapplication.MainActivity.onCreate(MainActivity.java:21)
at android.app.Activity.performCreate(Activity.java:6679)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
不可能因为
A Fragment
不是 View
,Butterknife 的 @BindView
用于绑定 View,而不是 Fragment。
您可以使用 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();
}
}
}
}
}
}
在你的activity中你可以这样做
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);
}
}
尝试添加片段运行时。
这是一个例子。
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();
}
这样您就可以从 activity.
调用片段中的接口方法
是否可以通过接口获取SomeFragment?我不想使用 FragmentManager,因为在我的原始代码中 MainActivity 是一个片段。
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>
FATAL EXCEPTION: main Process: com.tamtam.myapplication, PID: 29138 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tamtam.myapplication/com.tamtam.myapplication.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void com.tamtam.myapplication.MainActivity$FragmentCallback.test()' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) at android.os.Handler.dispatchMessage(Handler.java:102) at android.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.main(ZygoteInit.java:776) Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.tamtam.myapplication.MainActivity$FragmentCallback.test()' on a null object reference at com.tamtam.myapplication.MainActivity.onCreate(MainActivity.java:21) at android.app.Activity.performCreate(Activity.java:6679) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119)
不可能因为
A Fragment
不是 View
,Butterknife 的 @BindView
用于绑定 View,而不是 Fragment。
您可以使用 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();
}
}
}
}
}
}
在你的activity中你可以这样做
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);
}
}
尝试添加片段运行时。
这是一个例子。
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();
}
这样您就可以从 activity.
调用片段中的接口方法