如何创建一个接口从Fragment获取信息并传递给Android Activity?

4
在过去的几天里,我一直在努力使用简单的片段(我使用两次)构建一个安卓应用程序。我想将片段的EditText框中的内容传递到新的活动中。我只是无法弄清楚如何从这些片段中获取这些内容。我目前所拥有的是这个:
我有我的edit_text_fragment.xml:
<?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"
    android:orientation="vertical" >
    <EditText 
        android:id="@+id/my_edit_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="my hint" />
</LinearLayout>

对应的MyEditTextFragment.java如下:

public class MyEditTextFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.edit_text_fragment, container, false);
        return view;
    }
}

然后我在main.xml中两次使用这个片段,像这样:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <fragment 
        android:id="@+id/detailfragment_placeholder"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        class="com.example.fragmenttester5.MyEditTextFragment" />
    <fragment 
        android:id="@+id/detailfragment_placeholder2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        class="com.example.fragmenttester5.MyEditTextFragment" />
    <Button 
        android:id="@+id/submit_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Submit all of it" />
</LinearLayout>

在我的MainActivity中,我将按钮连接到了一个新的活动:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button submitButton = (Button) findViewById(R.id.submit_button);
        submitButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v){
                Intent intent = new Intent(MainActivity.this, OtherActivity.class);
                intent.putExtra("result1", "the_result_from_the_first_editText");
                intent.putExtra("result2", "the_result_from_the_second_editText");
                startActivity(intent);
            }
        });
    }
}

我认为我现在需要在片段中定义某种接口,但我找不到方法。我阅读了一些例子和教程(如这个),但它们对我来说完全没有意义。我不理解给出的代码,也不知道如何针对我的用例进行调整。
所以我的问题是:有人可以帮助我从活动中获取片段的内容吗?如果有例子就更好了,因为我只是在这里碰壁。
4个回答

18

你说得对,这是一种将数据从Fragment传递给Activity的标准方式。

基本上,你需要定义一个接口 Listener,然后Activity实现该接口,并在Fragment中注册自己作为Listener。

下面是一个简单的示例:

Fragment

class MyFragment extends Fragment {

    interface Listener {
        public void somethingHappenedInFragment(Object... anyDataYouWantToPassToActivity);
    }

    private Listener mListener;

    public void setListener(Listener listener) {
        mListener = listener;
    }

    // ... your code ...

    // Now here you pass the data to the activity
    mListener.somethingHappenedInFragment(some, data);

    // ... more of your code
 }

活动

public MyActivity extends Activity implements MyFragment.Listener {

    // ... your code ...

    // creating the Fragment
    MyFragment f = new MyFragment();

    // register activity as listener
    f.setListener(this);

    // ... more of your code

    // implementation of MyFragment.Listener interface
    @Override
    public void somethingHappenedInFragment(Object... anyDataYouWantToPassToActivity) {
        // here you have the data passed from the fragment.
        for (Object o : anyDataYouWantToPassToActivity {
            System.out.println(o.toString();
        }
    }

}

请在Fragment中重写onAttach()方法,否则可能会在mListener上出现NPE。 - Prince

4
在高层次上,你通常需要使用片段来解决两个任务。第一个是将数据从Activity传递到Fragment。第二个是将数据从Fragment传递到Activity。
Activity知道它包含哪些Fragments,因为它创建了它们,所以通过这种方式进行通信很容易——只需在Fragment本身上调用方法。但反过来不成立;Fragments可能会附加到任意数量的随机Activities上,因此它不知道它的父亲是谁。
解决方案是实现一个接口,Activity实现该接口,而Fragment则知道如何与之通信。这样,你的Fragment就有了它知道如何交流的东西。这里有具体的代码示例: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity(特别是请查看“创建回调事件以与Activity通信”的代码示例)。

好的,我大概到这个程度了。现在我需要在片段中创建一个接口,并在活动中实现它。我只是不明白如何做。如果你能提供一些代码片段来帮助我入门就太好了。 - kramer65
这里实际上根本不需要接口。操作发生在“Activity”中,而不是“Fragment”(按钮不在片段中)。请参见我的答案。 - Paul Burke

2

如果事件在Fragment中发生,您需要创建一个接口与Activity进行通信。对于这种情况,您可以在Fragment中创建一个可访问的方法,供Activity调用。所以:

public class MyEditTextFragment extends Fragment {
    private EditText mEditText;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.edit_text_fragment, container, false);
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mEditText = (EditText) getView().findViewById(R.id.my_edit_text);
    }

    public Editable getText() {
        return mEditText.getText();
    }
}

那么

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final MyEditTextFragment fragment1 = (MyEditTextFragment)
            getFragmentManager().findFragmentById(R.id.detailfragment_placeholder);

        final MyEditTextFragment fragment2 = (MyEditTextFragment)
            getFragmentManager().findFragmentById(R.id.detailfragment_placeholder2);

        Button submitButton = (Button) findViewById(R.id.submit_button);
        submitButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v){

                String firstResult = fragment1.getText().toString();
                String secondResult = fragment2.getText().toString();

                Intent intent = new Intent(MainActivity.this, OtherActivity.class);
                intent.putExtra("result1", firstResult);
                intent.putExtra("result2", secondResult);
                startActivity(intent);
            }
        });
    }
}

假设您在 FragmentTransaction 中分配了 Fragment 标签。请确保检查空的 Fragments(为简洁起见省略)。

实际上,您的片段是通过XML填充的,因此根本不需要调用getFragmentManager().findFragmentByTag。现在正在更新答案。 - Paul Burke
2
你太棒了!你基本上让我整个周末都很棒!谢谢你!:D - kramer65
你能回答这个问题吗?This One - user7688701

0

Activity将从Fragment的updateDetail()方法接收数据

//// Activity 
public class RssfeedActivity extends Activity implements MyListFragment.OnItemSelectedListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rssfeed);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.d("Annv - Fragment", "onClick here");
            }
        });
    }

    // if the wizard generated an onCreateOptionsMenu you can delete
    // it, not needed for this tutorial

    @Override
    public void onRssItemSelected(String link) {
        //        DetailFragment fragment = (DetailFragment) getFragmentManager()
        //                .findFragmentById(R.id.detailFragment);
        //        if (fragment != null && fragment.isInLayout()) {
        //          fragment.setText(link);
        //        } 
        //        Intent start = new Intent(this, RssfeedSecondActivity.class);
        //        startActivity(start);
        DetailFragment fragment = (DetailFragment) getFragmentManager()
                .findFragmentById(R.id.detailFragment);
        if (fragment != null && fragment.isInLayout()) {
            fragment.setText(link);
        }
    }

}

/// Fragment
public class MyListFragment extends Fragment {

    private OnItemSelectedListener listener;
    private OnItemStartActivityListener listenerStartAct;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_rsslist_overview,
                container, false);
        Button button = (Button) view.findViewById(R.id.button1);
        Log.d("Annv - Fragment", "run on " + getActivity().toString());
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                updateDetail();
            }
        });
        return view;
    }

    public interface OnItemSelectedListener {
        public void onRssItemSelected(String link);
    }

    public interface OnItemStartActivityListener {
        public void onRssStartActivity(String link);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof OnItemSelectedListener) {
            Log.d("Annv - Fragment", "activity " + activity.getLocalClassName());
            listener = (OnItemSelectedListener) activity;
        } else if (activity instanceof OnItemStartActivityListener) {
            Log.d("Annv - Fragment", "activity " + activity.getLocalClassName());
            listenerStartAct = (OnItemStartActivityListener) activity;
        } else {
            throw new ClassCastException(activity.toString()
                    + " must implemenet MyListFragment.OnItemSelectedListener");
        }
    }

    // May also be triggered from the Activity
    public void updateDetail() {
        // create fake data
        //        String newTime = String.valueOf(System.currentTimeMillis());
        //        // Send data to Activity
        //        listenerStartAct.onRssItemSelected(newTime);
        if (getActivity() instanceof OnItemSelectedListener) {
            listener.onRssItemSelected("start start");
        } else {
            String newTime = String.valueOf(System.currentTimeMillis());
            listenerStartAct.onRssStartActivity(newTime);
        }

    }

}

代码转储不是答案。请编辑您的答案,解释您的代码以及它如何回答问题。 - Charles

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接