Truyền dữ liệu giữa một đoạn và hoạt động chứa của nó


176

Làm thế nào tôi có thể truyền dữ liệu giữa một đoạn và hoạt động chứa của nó? Có một cái gì đó tương tự như truyền dữ liệu giữa các hoạt động thông qua ý định?

Tôi đã đọc nó, nhưng nó không giúp được gì nhiều:
http://developer.android.com/guide/topics/fundamentals/fragments.html#CransicatingWithActivity


Điều đó là không đủ? Bạn có thể gửi bất cứ điều gì bạn muốn, có thể bạn có thể giải thích thêm, bạn muốn đạt được điều gì?
Marcin Milejski

Từ tài liệu tôi không hiểu làm thế nào, ví dụ, tôi sẽ chuyển một giá trị hoặc một chuỗi từ hoạt động sang đoạn hoặc ngược lại. Cảm ơn
tyb

2
Cách tốt nhất để xử lý các cuộc gọi không đồng bộ từ các đoạn và trả lại dữ liệu cho chúng là triển khai BroadcastReceivers ở cả hai phía. Dù sao thì bạn cũng nên làm cho nó không đồng bộ nếu bạn đang làm việc với số lượng phân đoạn không cụ thể.
Marek Sebera

@astaisher_malade Không, làm việc cho tôi
Vadim Kotov

Câu trả lời:


211

Trong mảnh của bạn, bạn có thể gọi getActivity().

Điều này sẽ cung cấp cho bạn quyền truy cập vào hoạt động đã tạo ra đoạn. Từ đó bạn rõ ràng có thể gọi bất kỳ loại phương thức truy cập nào có trong hoạt động.

ví dụ: đối với phương thức được gọi getResult()trên Hoạt động của bạn:

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

86
Vì bạn đang truy cập một chức năng trong Hoạt động CỦA BẠN (chứ không phải hoạt động Android gốc), bạn sẽ cần thực hiện cuộc gọi getActivity (): ((MyActivity) getActivity ()). GetResult ();
Nick

3
Làm thế nào sẽ có thể là phương pháp trở lại, từ mảnh đến hoạt động?
Vasil Valchev

6
@VasilValchev, bạn có thể tạo giao diện và buộc hoạt động thực hiện nó và sau đó gọi một phương thức từ trong đoạn của bạn để truyền dữ liệu. Sử dụng phương thức onAttach để kiểm tra xem hoạt động có thực hiện giao diện không.
Ivan Nikolov

3
Câu trả lời tuyệt vời từ @IvanNikolov. Bạn có thể tìm thấy lời giải thích kỹ lưỡng tại Liên kết đào tạo mảnh vỡ
bogdan

8
Đây không phải là một thực hành tốt cũng không phải là mô hình. Câu trả lời với giao diện là chính xác.
moictab

303

Hãy thử sử dụng các giao diện.

Bất kỳ phân đoạn nào sẽ chuyển dữ liệu trở lại hoạt động chứa nó nên khai báo một giao diện để xử lý và truyền dữ liệu. Sau đó, đảm bảo hoạt động chứa của bạn thực hiện các giao diện đó. Ví dụ:

JAVA

Trong đoạn của bạn, khai báo giao diện ...

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

Sau đó, kết nối việc triển khai giao diện của lớp chứa với đoạn trong phương thức onAttach, như vậy:

OnDataPass dataPasser;

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

Trong phần của bạn, khi bạn cần xử lý việc truyền dữ liệu, chỉ cần gọi nó trên đối tượng dataPasser:

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

Cuối cùng, trong hoạt động chứa của bạn thực hiện OnDataPass ...

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

KOTLINE

Bước 1. Tạo giao diện

interface OnDataPass {
    fun onDataPass(data: String)
}

Bước 2. Sau đó, kết nối việc triển khai giao diện của lớp chứa với đoạn trong phương thức onAttach (YourFragment), như vậy:

lateinit var dataPasser: OnDataPass

override fun onAttach(context: Context) {
    super.onAttach(context)
    dataPasser = context as OnDataPass
}

Bước 3. Trong đoạn của bạn, khi bạn cần xử lý việc truyền dữ liệu, chỉ cần gọi nó trên đối tượng dataPasser:

fun passData(data: String){
    dataPasser.onDataPass(data)
}

Bước 4. Cuối cùng, trong hoạt động của bạn thực hiện OnDataPass

class MyActivity : AppCompatActivity(), OnDataPass {}

override fun onDataPass(data: String) {
    Log.d("LOG","hello " + data)
}

1
Cảm ơn câu trả lời tốt, đến điểm. Điều này cũng được giải thích rất độc đáo ở đây . Điều tôi không nhận ra là bạn có thể triển khai nhiều giao diện, tôi đã thực hiện ActionBar.TabListenervà phải thêm một giao diện bổ sung.
Eugene van der Merwe

5
Đây chắc chắn là con đường để đi và theo tôi là con đường DUY NHẤT. Và cung cấp hai cách tương tác giữa Hoạt động và Đoạn. Cũng sẽ cho phép một phương tiện giao tiếp giữa các đoạn khi bạn có nhiều đoạn trong một hoạt động cho dù thông qua các tab hoặc bố cục nhiều đoạn.
Christopher

1
Có một điều tôi đang tự hỏi ... Đây là câu trả lời chính thức, và từ trang web dành cho nhà phát triển chính thức, họ nói rằng đây là cách phù hợp để kết hợp với Frag-act-Frag, nhưng tại sao thậm chí có thể thực hiện điều đó thông qua việc truyền getActivity ( )?
unmultimedio

3
Tại sao ai đó cần một giao diện bổ sung để làm điều đó? Tại sao bạn xem xét giải pháp sau đây xấu hoặc giải pháp của bạn tốt hơn? ((MyActivity) getActivity) .myMethod (...)
spacifici

3
onAttach (Hoạt động hoạt động) không được chấp nhận, vui lòng sử dụng onAttach (Bối cảnh bối cảnh) thay thế.
Chris.C

23

Cách tiếp cận dễ nhất nhưng không được khuyến nghị

Bạn có thể truy cập dữ liệu hoạt động từ đoạn:

Hoạt động:

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

Miếng:

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

5
Điều này thêm khớp nối cao vào mã của bạn và là một thực tiễn xấu. Bây giờ bạn không thể sử dụng Mảnh vỡ trong bất kỳ Hoạt động nào khác ngoàiMyActivity
AmeyaB

Tại sao cách này được coi là thực tiễn xấu và giao diện chỉ là giải pháp của câu hỏi này?
androidXP

AmeyaB nếu tất cả hoạt động mở rộng từ BaseActivity hoặc chúng tôi sử dụng nó như BaseActivity hoạt động = (BaseActivity) getActivity (); sau đó nó sẽ hoạt động trên tất cả các hoạt động
Zar E Ahmer

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

14
Đây là cách lấy nó trong Fragment, nhưng làm thế nào để bạn đặt nó trong lớp gọi đoạn đó nếu bạn có đoạn của mình trong tệp bố cục xml.
Zapnologica

17

Truyền dữ liệu giữa một đoạn và hoạt động chứa của nó

Hoạt động:

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

Miếng:

Đọc giá trị trong đoạn

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

xin chào @Elenasys. Làm thế nào tôi có thể gửi dữ liệu bó trở lại đoạn từ hoạt động. Tôi đã đi từ mảnh này sang hoạt động khác và tôi cần quay lại mảnh đã được tạo (chỉ gọi onStart, onResume, ...) và cần dữ liệu mà tôi có thể có được trong hoạt động. Có cách nào để làm điều đó hay tôi đang làm gì đó sai?
Michal Morasta

7

Tôi không biết đây có phải là cách tốt nhất hay không Bu tôi đã tìm kiếm trên google khá lâu trong khi tìm cách tôi có thể chuyển Bundle từ một đoạn sang hoạt động container của nó nhưng thay vào đó, tất cả những gì tôi tìm thấy là gửi dữ liệu từ hoạt động đến đoạn (điều này hơi khó hiểu đối với tôi khi tôi là người mới).

Sau đó, tôi đã thử một cái gì đó của riêng tôi mà chính xác làm việc cho tôi như tôi muốn. Vì vậy, tôi sẽ đăng nó ở đây trong trường hợp ai đó như tôi đang tìm kiếm điều tương tự.

// Truyền dữ liệu từ 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);

// Lấy dữ liệu từ gói từ hoạt động chứa của nó.

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

Giao diện là một trong những giải pháp tốt nhất:

Giao diện keo:

public interface DataProviderFromActivity {

    public String getName();
    public String getId);

}  

Hoạt động của tôi:

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

Xin chào @HassanMakarov Tôi thích giao diện của bạn, đơn giản và sạch sẽ. Tôi có một vấn đề mặc dù. Tôi không biết nó có đặc trưng cho người xem của tôi không nhưng tôi chỉ nhận được dữ liệu trong tối đa 2 phân đoạn một lần? Các chuỗi "Makarov" & "sys533" xuất hiện trong các đoạn 1 & 2 khi hoạt động được tạo nhưng các chuỗi không xuất hiện trong đoạn 3 cho đến khi đoạn 2 hoặc 3 được chọn? Có ý kiến ​​gì không?
JC23

@ JC23 Tôi đoán vấn đề có liên quan đến giao dịch mảnh. Đoạn nào được đặt khi MainActivity được khởi chạy?
Hassan Tareq

@ JC23 Tôi làm gì: thay vì Tab / ViewPager Tôi sử dụng Thanh công cụ & NavigationView. Trong onNavestionItemSelected () tôi thực hiện các giao dịch phân đoạn để đặt các phân đoạn tương ứng.
Hassan Tareq

2

Tôi đã sử dụng một AppCompatActivity thực hiện Trình nghe ngày. Các mảnh vỡ là một điều cần thiết vì tôi cần mã hóa bộ chọn phạm vi ngày. Và tôi cũng cần container để nhận các ngày đã chọn để đưa chúng trở lại hoạt động chính.

Đối với hoạt động của container, đây là khai báo lớp:

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

Và các giao diện cho các cuộc gọi lại:

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

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

Các cuộc gọi lại là chuỗi vì ngày là tham số trong một truy vấn chọn.

Mã cho các đoạn (dựa trên đoạn ngày ban đầu):

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

}

Để soạn thảo vùng chứa + đoạn, tôi đã sử dụng ViewPager (AppCompat) với một lớp tùy chỉnh mở rộng FragmentPagerAd CHƯƠNG. Không có hộp thoại.


2

Đơn giản là bạn có thể sử dụng EventBus thật dễ dàng và hoạt động tốt

EventBus trong 3 bước

  1. Xác định các sự kiện:

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

  2. Chuẩn bị người đăng ký: Khai báo và chú thích phương thức đăng ký của bạn, tùy chọn chỉ định chế độ luồng:

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

Đăng ký và hủy đăng ký thuê bao của bạn. Ví dụ: trên Android, các hoạt động và phân đoạn thường phải đăng ký theo vòng đời của chúng:

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
  1. Đăng sự kiện:

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


1

Tôi biết điều này có thể là muộn. Nhưng tôi cũng luôn lạc lối về câu hỏi này. Tôi đang chia sẻ liên kết này ... bởi vì đây có thể là lời giải thích tốt nhất tôi từng tìm thấy trên web cho việc này. Điều này giải quyết Fragment to Activity & Fragment to Fragment !

Giải quyết và giải thích thực sự tốt


0

Điều này đang làm việc cho tôi ..

trong Activity thêm phương thức này

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

và trong Fragment thêm dòng này

((YourActivity)getContext).GetData("your data here");

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

Một cách đơn giản khác để lấy dữ liệu, được truyền từ một hoạt động khác, trong một đoạn trong hoạt động chứa: ví dụ:

Activity_A => Activity_B (Đoạn)

Trong Activity_A của bạn, bạn tạo một ý định như bạn đang gửi dữ liệu (Chuỗi ở đây) cho một hoạt động khác:

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

trong Đoạn của bạn, có trong Activity_B của bạn:

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

getBaseContext()cho tôi lỗi sau:The method getBaseContext() is undefined for the type new View.OnClickListener(){}
Si8
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.