Android中的碎片间通信

6
我在Android编程方面处于初学者水平,因此我需要您的真诚帮助。请有人帮帮我。
我正在尝试使用片段构建滑动UI。
我的实际疑问是...我有一个片段(称为A片段),它有一个TextView和一个Button,并且另一个片段(称为B片段)。它里面有一个TextView。当我按下A片段中的按钮时,我需要在B片段的TextView中显示A片段的TextView内容。我尝试了很多方法,但不幸的是我没有得到正确的输出。我相信你们知道这个问题,请帮帮我。
谢谢。

你应该将文本存储在父Activity中,并在加载FRAGMENT B时将其传递给它。 - dmaxi
@dmaxi 但我不知道如何在父 Activity 中存储文本。 - Sam
创建一个字符串类型的成员变量,并不要忘记在onSaveInstanceState()回调中将其保存到Bundle中。您还应该阅读Activity和Fragment的JavaDoc。 - dmaxi
@dmaxi,你能给个例子吗?这样会更有帮助。 - Sam
6个回答

19

应该通过监听器来完成,这样片段仍然不会相互依赖,并且可以在单窗格或双窗格模式下使用。活动应该处理两个片段的监听器。

这是一个包含两个片段的活动示例:

package com.example;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;

import com.example.fragment.FragmentA;
import com.example.fragment.FragmentA.TextChangeListener;
import com.example.fragment.FragmentB;

public class ActivityAB extends FragmentActivity {

    FragmentA fragmentA;
    FragmentB fragmentB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ab);

        FragmentManager manager = getSupportFragmentManager();
        fragmentA = (FragmentA) manager.findFragmentById(R.id.fragmentA);
        fragmentB = (FragmentB) manager.findFragmentById(R.id.fragmentB);

        fragmentA.setTextChangeListener(new TextChangeListener() {

            @Override
            public void onTextChange(CharSequence newText) {
                fragmentB.updateTextValue(newText);
            }
        });
    }

}

这里是Fragment A,它具有自定义的文本更改事件监听器。

package com.example.fragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import com.example.R;

public class FragmentA extends Fragment {

    TextChangeListener listener;

    public interface TextChangeListener {
        public void onTextChange(CharSequence newText);
    }

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

        Button btn = (Button) view.findViewById(R.id.button1);
        final TextView textView = (TextView) view.findViewById(R.id.textView1);

        btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (null != listener) {
                    listener.onTextChange(textView.getText());
                }

            }
        });
        return view;
    }

    public void setTextChangeListener(TextChangeListener listener) {
        this.listener = listener;
    }
}

这里是片段B,它具有可更新文本字段的公共方法:

package com.example.fragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.R;

public class FragmentB extends Fragment {

    TextView textView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_b, container, false);
        textView = (TextView) view.findViewById(R.id.textView1);
        return view;
    }

    public void updateTextValue(CharSequence newText) {
        textView.setText(newText);
    }
}

ActivityAB的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:baselineAligned="false"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.example.fragment.FragmentA"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/fragmentB"
        android:name="com.example.fragment.FragmentB"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

片段 A 的 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" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show" />

</LinearLayout>

片段 B 的 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" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="(here will be text)"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

嗨,谢谢你的回复。但这对我没有用。还有一件事,我在activity ab中没有两个单独的片段布局(当然我有两个片段类和相应的布局xml文件)……相反,我只有一个片段布局,我正在动态更改内容。请问你能否再为我尝试一次? - Sam
方法 onTextChange 将在按钮点击期间被调用。因此,请使用此回调将片段 A 替换为片段 B,并设置您收到的文本,例如 fragmentB.updateTextValue(newText); this.showFragmentB(); - andrew
这个建议并不适用于一般情况。如果您正在使用子片段呢?父片段和子片段可能需要相互通信,而无需一路到达包含它们的 Activity。在某些情况下,根 Activity 可能会承载整个应用程序(例如:基于选项卡的应用程序)。没有办法将每个子组件之间的每个通信都通过一个地方路由(这是单一职责反模式的重大违规)。 - Marchy

2

看起来你的设置可能是这样的 - MainActivity包含FragmentA [已添加]和FragmentB [已添加]。 对于这种情况,我会通过MainActivity在两个片段之间委派消息/操作。 允许MainActivity处理消息/操作还可以促进在Fragments之间更复杂的“特殊”编排。 例如:

public interface FragmentCommunicator
{
    public void sendMessage ( String broadcastMessage );
    public void takeAction ( String name, int action, Fragment frag );
}

public class MainActivity extends Activity implements FragmentCommunicator
{
    Fragment fragA;
    Fragment fragB;
    ...
    @Override
    public void sendMessage ( String msg )
    {
        if ( msg.Contains("Send To fragA") )
            fragA.receiveMsg(msg);
        ...
    }
    @Override
    public void takeAction ( String name, int action, Fragment frag )
    {
    if ( action == CLOSE )
            removeFragment( name, frag );
        ...
    }
}

public class FragmentA extends Fragment
{
    ...
@Override
public void onClick(View v)
{   
     FragmentCommunicator inter = (FragmentCommunicator) getActivity();
     inter.sendMessage("the txt/information/etc you want to send to fragB");    
}
}

public class FragmentB extends Fragment
{
    ...
    public void receiveMsg ( String msg )
    {
        textView.setText(msg);
    }
}

我忘记发布 FragmentA 的发送部分了。 希望这可以帮到你。


0

两个片段之间的通信应始终通过它们的片段活动进行,以保持片段之间的松耦合。因此,如果您想将一些数据从一个片段A发送到另一个片段B,则可以创建侦听器并在片段活动中实现它,在片段A内部使用该侦听器触发事件并将数据发送到片段活动。现在,片段活动也将拥有片段B的对象,因此片段活动可以直接调用片段B的方法并将数据发送到片段B...


0

我喜欢将活动作为片段之间通信的中间人。但我还喜欢使用event bus架构,它也提供了解耦。


0

-1

这其实很简单,只需按照以下步骤操作:

  1. 你已经创建了两个片段A和B,现在创建它们的“大脑”,即Java类文件。我们称它们为JClass A(用于片段A)和JClass B(用于片段B)。

2.在Frag A中有一个按钮,所以进入JClass A,在那里获取用户输入的字符串文本和按钮按下事件,如下所示: // 只需覆盖onCreate方法。

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.<name of your fragment A.xml file>,container,false);

    userInput = (EditText)view.findViewById(R.id.<Id that you gave to EditText field in which user enters text>);

    Button myButton = (Button)view.findViewById(R.id.<id of your Button>);
    myButton.setOnClickListener(
            new Button.OnClickListener(){
                public void onClick(View v){
                    JClassB.setText(userInput.getText().toString());/*Replace JClassB with the java class of Fragment B*/

                }
            }
    );

    return view;
}
  • 最后,在您的JClass B(片段B的Java文件)中:

    public class BottomSectionFrag extends Fragment {

    private static TextView userText;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmentB, container, false);
        userText = (TextView)view.findViewById(R.id.userText);
        return view;
    }
    public static void setText(String text){
        userText .setText(text);
    
    }
    

    }

  • 哇!!

    附言:这是我在 stackOverFlow 上的第一篇帖子 :D

    平安出去。


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