在片段及其容器活动之间传递数据

时间:2012-02-18 17:10:13

标签: android android-fragments

如何在片段及其容器活动之间传递数据?是否有类似于通过意图在活动之间传递数据的东西?

我读过这篇文章,但没有多大帮助:
http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity

16 个答案:

答案 0 :(得分:278)

尝试使用接口。

任何应该将数据传递回其包含活动的片段都应该声明一个接口来处理和传递数据。然后确保包含的活动实现了这些接口。例如:

在你的片段中,声明接口......

public interface OnDataPass {
    public void onDataPass(String data);
}

然后,连接包含的类'在onAttach方法中实现片段的接口,如下所示:

OnDataPass dataPasser;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    dataPasser = (OnDataPass) context;
}

在你的片段中,当你需要处理数据传递时,只需在dataPasser对象上调用它:

public void passData(String data) {
    dataPasser.onDataPass(data);
}

最后,在您的包含活动中实施 OnDataPass ...

@Override
public void onDataPass(String data) {
    Log.d("LOG","hello " + data);
}

答案 1 :(得分:192)

在您的片段中,您可以拨打 getActivity()

这将允许您访问创建片段的活动。从那里你可以明显地调用活动中的任何类型的访问器方法。

e.g。对于您的活动中名为getResult()的方法:

((MyActivity) getActivity()).getResult();

答案 2 :(得分:21)

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Bundle b = getActivity().getIntent().getExtras();
            wid = b.getString("wid");
            rid = b.getString("rid");
            View view = inflater.inflate(R.layout.categoryfragment, container, false);
    return view;
 }

答案 3 :(得分:21)

最简单的方法,但不推荐

您可以从片段访问活动数据:

<强>活动:

public class MyActivity extends Activity {

    private String myString = "hello";

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

    public String getMyData() {
        return myString;
    }
}

<强>片段:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        MyActivity activity = (MyActivity) getActivity();
        String myDataFromActivity = activity.getMyData();
        return view;
    }
}

答案 4 :(得分:13)

在片段及其容器活动之间传递数据

<强>活动:

        Bundle bundle = new Bundle();
        bundle.putString("message", "Alo Elena!");
        FragmentClass fragInfo = new FragmentClass();
        fragInfo.setArguments(bundle);
        transaction.replace(R.id.fragment_single, fragInfo);
        transaction.commit();

<强>片段:

读取片段中的值

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        String myValue = this.getArguments().getString("message");
        ...
        ...
        ...
        }

答案 5 :(得分:6)

我不知道这是不是最好的方法 我一直在google上搜索了一段时间,我发现如何将一个Bundle从一个片段传递到它的容器活动,但我发现所有这些都是将数据从活动发送到片段(这对我来说有点混乱,因为我&#39; ma newbie)。

后来我尝试了自己的东西,这对我来说非常有用。所以我会在这里发布一些像我这样的人寻找同样的事情。

//从Fragment传递数据。

Bundle gameData = new Bundle();
        gameData.putStringArrayList(Constant.KEY_PLAYERS_ARR,players);
        gameData.putString(Constant.KEY_TEAM_NAME,custom_team_name);
        gameData.putInt(Constant.KEY_REQUESTED_OVER,requestedOver);

        Intent intent = getActivity().getIntent();
        intent.putExtras(gameData);

//从包中获取数据包的容器活动。

Bundle gameData = getIntent().getExtras();
        if (gameData != null)
        {
            int over = gameData.getInt(Constant.KEY_REQUESTED_OVER);
            ArrayList<String> players = gameData.getStringArrayList(Constant.KEY_PLAYERS_ARR);
            String team = gameData.getString(Constant.KEY_TEAM_NAME);

        }
        else if (gameData == null)
        {
            Toast.makeText(this, "Bundle is null", Toast.LENGTH_SHORT).show();
        }

答案 6 :(得分:4)

接口是最好的解决方案之一:

胶水界面:

public interface DataProviderFromActivity {

    public String getName();
    public String getId);

}  

MyActivity:

public class MyActivity implements DataProviderFromActivity{

    String name = "Makarov";
    String id = "sys533";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

    public String getName(){
        return name;
    };
    public String getId(){
        return id;
    };
}

MyFragment:

public class MyFragment extends Fragment{

    String fragName = "";
    String fragId = "";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

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

        DataProviderFromActivity myActivity= (DataProviderFromActivity) getActivity();
        fragName = myActivity.getName();
        fragId = myActivity.getId();

        ... ... ... ... ... .... .... 
        ... ... ... ... ... .... .... 

        updateFragmentView();
    }
}

答案 7 :(得分:2)

我使用了一个实现Date Listeners的AppCompatActivity。碎片是必要的,因为我需要编写日期范围选择器。我还需要容器来接收选定的日期以将它们返回到父活动。

对于容器活动,这是类声明:

public class AppCompatDateRange extends AppCompatActivity implements
    DateIniRangeFragment.OnDateIniSelectedListener, DateFimRangeFragment.OnDateFimSelectedListener

回调的接口:

@Override
public void onDateIniSelected(String dataIni) {
    Log.i("data inicial:", dataIni);
}

@Override
public void onDateFimSelected(String dataFim) {
    Log.i("data final:", dataFim);
}

回调是字符串,因为日期是查询选择中的参数。

片段的代码(基于初始日期片段):

public class DateIniRangeFragment extends Fragment {
OnDateIniSelectedListener callbackIni;

private DatePicker startDatePicker;

public DateIniRangeFragment() {
    ///required empty constructor
}

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

///through this interface the fragment sends data to the container activity
public interface OnDateIniSelectedListener {
    void onDateIniSelected(String dataIni);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ///layout for the fragment
    View v = inflater.inflate(R.layout.date_ini_fragment, container, false);

    ///initial date for the picker, in this case, current date
    startDatePicker = (DatePicker) v.findViewById(R.id.start_date_picker_appcompat);
    Calendar c = Calendar.getInstance();
    int ano = c.get(Calendar.YEAR);
    int mes = c.get(Calendar.MONTH);
    int dia = c.get(Calendar.DAY_OF_MONTH);
    startDatePicker.setSpinnersShown(false);
    startDatePicker.init(ano, mes, dia, dateSetListener);

    return v;
}

///listener that receives the selected date
private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {
    public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        if (view.isShown()) { ///if the datepicker is on the screen
            String sDataIni = year + "-" + (monthOfYear + 1) + "-" + dayOfMonth;
            callbackIni.onDateIniSelected(sDataIni); //apply date to callback, string format
        }
    }
};

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    /*
    * this function guarantees that the container activity implemented the callback interface
    * */
    try {
        callbackIni = (OnDateIniSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " deve implementar OnDateIniSelectedListener");
    }
}

}

为了组合容器+片段,我使用ViewPager(AppCompat)和一个扩展FragmentPagerAdapter的自定义类。没有对话框。

答案 8 :(得分:2)

只需使用EventBus即可轻松实现

EventBus分3步

  1. 定义事件:

    public static class MessageEvent { /* Additional fields if needed */ }

  2. 准备订阅者:声明并注释您的订阅方法, 可选地指定线程模式:

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {/* Do something */};

  3. 注册并取消注册您的订阅者。例如在Android上,     活动和片段通常应根据他们的注册     生命周期:

     @Override
     public void onStart() {
         super.onStart();
         EventBus.getDefault().register(this);
     }
    
     @Override
     public void onStop() {
         super.onStop();
         EventBus.getDefault().unregister(this);
     }
    
    1. 发布活动:

      EventBus.getDefault().post(new MessageEvent());

答案 9 :(得分:1)

我知道这可能要晚了。但是我也总是在这个问题上迷路。我正在分享此链接...,因为这可能是我在网上找到的最佳解释。这样可以解决从片段到活动从片段到片段

Solved & Explained really well

答案 10 :(得分:0)

这对我有用..

在Activity中添加此方法

Laravel API

并在Fragment中添加此行

    public void GetData(String data)
     {
        // do something with your data        
     }

答案 11 :(得分:0)

public class Fragmentdemo extends Fragment {

  public interface onDemoEventListener {
    public void demoEvent(String s);
  }

  onDemoEventListener demoEventListener;

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
        try {
          demoEventListener = (onDemoEventListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement onDemoEventListener");
        }
  }

  final String LOG_TAG = "TAG";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragmentdemo, null);

    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        demoEventListener.someEvent("Test text to Fragment1");
      }
    });
    enter code here
    return v;
  }
}

答案 12 :(得分:0)

我用来将数据从片段转换为活动的一种有效解决方案是:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names then click to launch.." title="Type in a name">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td><a href="https://germany.net/sweden">Germany</a></td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Italy</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>France</td>
  </tr>
</table>
</body>
</html>

答案 13 :(得分:0)

首先在你的 Fragment.java 中创建接口

 public interface SendDataInterface{
     public void sendData(String data);
 }

然后通过重写 onAttach(Context context) 方法在 Fragment.java 中创建一个 Activity 的引用

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    Activity activity =(Activity)context ;
    try{
        mSendDataInterface= (SendDataInterface) activity;
    }catch(RuntimeException e){
        throw new RuntimeException(activity.toString()+" must implement method");
    }
}

您的 Fragment.java 应如下所示:

public class FirstFragment extends Fragment {

private Button mButton;
private EditText mEditText;
SendDataInterface mSendDataInterface;

public FirstFragment(){ }

/**
 * We can not directly access the data of Fragment
 * So we should create an interface
 *
 */
 public interface SendDataInterface{
     public void sendData(String data);
 }


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view =  inflater.inflate(R.layout.fragment_first, container, false);
    mButton = view.findViewById(R.id.button);
    mEditText = view.findViewById(R.id.editText);

    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String data= mEditText.getText().toString();
            mSendDataInterface.sendData(data);
        }
    });
    return view;
}

/**
 * We create a reference of activity
 */
@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    Activity activity =(Activity)context ;
    try{
        mSendDataInterface= (SendDataInterface) activity;
    }catch(RuntimeException e){
        throw new RuntimeException(activity.toString()+" must implement method");
    }
}

在 MainActivity.java 中实现 SendDataInterface 接口

public class MainActivity extends AppCompatActivity implements FirstFragment.SendDataInterface {

private TextView mTextView;

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

    mTextView = findViewById(R.id.textView);

    if(findViewById(R.id.container) != null){

        // Check if app is on Resume in Lifecycle
        if(savedInstanceState != null){
            return;
        }

        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .add(R.id.container,new FirstFragment(),null)
                .commit();
    }
}

@Override
public void sendData(String data) {
    mTextView.setText(data);
}
}

完成

答案 14 :(得分:0)

来自google official guide

Fragment 1.3.0-alpha04 开始,每个 FragmentManager 都实现了 FragmentResultOwner。这意味着 FragmentManager 可以充当片段结果的中央存储。此更改允许组件通过设置片段结果并侦听这些结果来相互通信,而无需这些组件相互直接引用。

在片段中: 子片段在其 FragmentManager 上设置结果。一旦片段开始,父级就会收到结果:

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}

在宿主活动中: 要在主机活动中接收片段结果,请使用 getSupportFragmentManager() 在片段管理器上设置结果侦听器。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportFragmentManager
                .setFragmentResultListener("requestKey", this) { requestKey, bundle ->
            // We use a String here, but any type that can be put in a Bundle is supported
            val result = bundle.getString("bundleKey")
            // Do something with the result
        }
    }
}

答案 15 :(得分:-11)

另一种从容器活动的片段中获取从另一个活动传递的数据的简单方法: 例如:

  

Activity_A =&gt; Activity_B(片段)

在您的Activity_A中,您创建一个意图,就像您将数据(此处为字符串)发送到另一个活动:

Intent intent = new Intent(getBaseContext(),Activity_B.class);
intent.putExtra("NAME", "Value");
startActivity(intent);
片段中的

,包含在您的Activity_B中:

String data = getActivity().getIntent().getExtras();