Melewati data antara fragmen dan aktivitas kontainernya

176

Bagaimana saya bisa mengirim data antara fragmen dan aktivitas kontainernya? Apakah ada yang serupa dengan mengirimkan data antar kegiatan melalui maksud?

Saya membaca ini, tetapi tidak banyak membantu:
http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity

tyb
sumber
Apakah itu tidak cukup? Anda dapat mengirim apa pun yang Anda inginkan, mungkin Anda bisa menjelaskan lebih lanjut, apa yang ingin Anda capai?
Marcin Milejski
Dari dokumen saya tidak mengerti bagaimana, misalnya, saya akan meneruskan nilai atau string dari aktivitas ke fragmen atau sebaliknya. Terima kasih
tyb
2
Cara terbaik untuk menangani panggilan tidak sinkron dari fragmen dan mengembalikan datanya adalah dengan mengimplementasikan BroadcastReceivers di kedua sisi. Anda tetap harus menjadikannya tidak sinkron jika Anda bekerja dengan jumlah fragmen yang tidak spesifik.
Marek Sebera
@punisher_malade Tidak, bekerja untuk saya
Vadim Kotov

Jawaban:

211

Dalam fragmen Anda, Anda dapat menelepon getActivity().

Ini akan memberi Anda akses ke aktivitas yang membuat fragmen. Dari sana Anda dapat dengan jelas memanggil segala jenis metode aksesor yang ada dalam aktivitas.

mis. untuk metode yang disebut getResult()di Aktivitas Anda:

((MyActivity) getActivity()).getResult();
Nick
sumber
86
Karena Anda mengakses fungsi dalam Aktivitas ANDA (dan bukan aktivitas Android induk), Anda harus melakukan panggilan getActivity (): ((MyActivity) getActivity ()). GetResult ();
Nick
3
Bagaimana mungkin metode kembali, dari fragmen ke aktivitas?
Vasil Valchev
6
@VasilValchev, Anda bisa membuat antarmuka dan memaksa aktivitas untuk mengimplementasikannya lalu memanggil metode dari dalam fragmen Anda untuk meneruskan data. Gunakan metode onAttach untuk memeriksa apakah aktivitas mengimplementasikan antarmuka.
Ivan Nikolov
3
Jawaban luar biasa dari @IvanNikolov. Anda dapat menemukan penjelasan menyeluruh di Link Pelatihan Fragmen
bogdan
8
Ini bukan praktik atau pola yang baik. Jawaban dengan antarmuka adalah yang benar.
moictab
303

Coba gunakan antarmuka.

Setiap fragmen yang harus meneruskan data kembali ke aktivitasnya yang mengandung harus menyatakan antarmuka untuk menangani dan meneruskan data. Kemudian pastikan aktivitas Anda yang mengandung mengimplementasikan antarmuka tersebut. Sebagai contoh:

JAWA

Dalam fragmen Anda, deklarasikan antarmuka ...

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

Kemudian, hubungkan implementasi kelas yang mengandung antarmuka ke fragmen dalam metode onAttach, seperti:

OnDataPass dataPasser;

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

Di dalam fragmen Anda, ketika Anda perlu menangani kelulusan data, sebut saja pada objek dataPasser:

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

Akhirnya, dalam kegiatan yang mengandung Anda yang mengimplementasikan OnDataPass ...

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

KOTLIN

Langkah 1. Buat Antarmuka

interface OnDataPass {
    fun onDataPass(data: String)
}

Langkah 2. Kemudian, hubungkan implementasi kelas yang berisi antarmuka ke fragmen dalam metode onAttach (YourFragment), seperti:

lateinit var dataPasser: OnDataPass

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

Langkah 3. Di dalam fragmen Anda, ketika Anda perlu menangani kelulusan data, sebut saja pada objek dataPasser:

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

Langkah 4. Terakhir, dalam aktivitas Anda mengimplementasikan OnDataPass

class MyActivity : AppCompatActivity(), OnDataPass {}

override fun onDataPass(data: String) {
    Log.d("LOG","hello " + data)
}
Harlo Holmes
sumber
1
Terima kasih jawaban yang bagus, to the point. Ini juga dijelaskan dengan sangat baik di sini . Apa yang saya tidak sadari adalah bahwa Anda dapat mengimplementasikan beberapa antarmuka, saya sudah menerapkan ActionBar.TabListenerdan harus menambahkan antarmuka tambahan.
Eugene van der Merwe
5
Ini jelas cara untuk pergi dan menurut saya cara HANYA untuk pergi. Dan menyediakan interaksi dua arah antara Aktivitas dan Fragmen. Juga akan memungkinkan sarana untuk berkomunikasi antara fragmen ketika Anda memiliki beberapa fragmen dalam satu aktivitas baik melalui tab atau tata letak multi frag.
Christopher
1
Ada sesuatu yang saya bertanya-tanya ... Ini adalah jawaban resmi, dan dari situs pengembang resmi mereka mengatakan ini adalah cara yang tepat untuk mengkomunikasikan frag-act-frag, tetapi mengapa itu mungkin dilakukan melalui casting getActivity (casting getActivity (casting getActivity) )?
unmultimedio
3
Mengapa seseorang memerlukan antarmuka tambahan untuk melakukan itu? Mengapa Anda menganggap solusi berikut ini buruk atau solusi Anda lebih baik? ((MyActivity) getActivity) .myMethod (...)
spacifici
3
onAttach (Aktivitas aktivitas) sudah tidak digunakan lagi, silakan gunakan onAttach (Konteks konteks).
Chris.C
23

Pendekatan termudah tetapi tidak Direkomendasikan

Anda dapat mengakses data aktivitas dari fragmen:

Aktivitas:

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

Pecahan:

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;
    }
}
Zar E Ahmer
sumber
5
Ini menambah kopling tinggi ke kode Anda dan merupakan praktik yang buruk. Sekarang Anda tidak dapat menggunakan Fragmen dalam Aktivitas apa pun selainMyActivity
AmeyaB
mengapa cara ini dianggap sebagai praktik buruk dan antarmuka hanya solusi dari pertanyaan ini?
androidXP
AmeyaB jika semua aktivitas meluas dari BaseActivity atau dan kami memberikannya seperti BaseActivity activity = (BaseActivity) getActivity (); maka itu akan bekerja pada semua kegiatan
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;
 }
Jeetu
sumber
14
Ini adalah bagaimana mendapatkannya di Fragmen, Tapi bagaimana Anda mengaturnya di kelas memanggil fragmen jika Anda memiliki fragmen Anda di file tata letak xml.
Zapnologica
17

Melewati data antara fragmen dan aktivitas kontainernya

Aktivitas:

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

Pecahan:

Membaca nilai dalam fragmen

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        String myValue = this.getArguments().getString("message");
        ...
        ...
        ...
        }
Jorgesys
sumber
halo @Elenasys. Bagaimana saya bisa mengirim data bundel kembali ke fragmen dari aktivitas. Saya beralih dari fragmen ke aktivitas dan saya harus kembali ke fragmen yang sudah dibuat (panggilan hanya onStart, onResume, ...) dan membutuhkan data yang dapat saya peroleh dalam aktivitas. Apakah ada cara bagaimana melakukannya atau saya melakukan sesuatu yang salah?
Michal Moravik
7

Saya tidak tahu apakah ini cara terbaik atau tidak, Bu saya telah mencari di Google cukup lama untuk menemukan bagaimana saya bisa mengirimkan sebuah Bundel dari sebuah fragmen ke aktivitas wadahnya, tetapi yang saya temukan hanyalah mengirim data dari aktivitas ke fragmen. (yang agak membingungkan bagi saya karena saya seorang pemula).

kemudian saya mencoba sesuatu milik saya sendiri yang benar-benar bekerja untuk saya seperti yang saya inginkan. jadi saya akan mempostingnya di sini jika seseorang seperti saya mencari hal yang sama.

// Melewati data dari Fragmen.

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

// Mendapatkan data dari bundel dari aktivitas kontainernya.

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();
        }
Buku Harian Beku
sumber
6

Antarmuka adalah salah satu solusi terbaik:

Antarmuka lem:

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();
    }
}
Hassan Tareq
sumber
Hai @HassanMakarov Saya suka antarmuka Anda, sederhana & bersih. Saya punya satu masalah. Saya tidak tahu apakah ini khusus untuk viewpager saya, tetapi saya hanya mendapatkan data paling banyak 2 fragmen sekaligus? String "Makarov" & "sys533" muncul dalam fragmen 1 & 2 saat aktivitas dibuat tetapi string tidak muncul dalam fragmen 3 sampai fragmen 2 atau 3 dipilih? Ada ide?
JC23
@ JC23 Saya kira masalahnya terkait dengan transaksi fragmen. Fragmen mana yang ditetapkan saat MainActivity diluncurkan?
Hassan Tareq
@ JC23 Apa yang saya lakukan: alih-alih Tab / ViewPager saya menggunakan Toolbar & NavigationView. Di onNavigationItemSelected () saya melakukan transaksi fragmen untuk mengatur fragmen yang sesuai.
Hassan Tareq
2

Saya menggunakan AppCompatActivity yang mengimplementasikan Date Listeners. Fragmen datang sebagai keharusan karena saya perlu kode pemilih rentang tanggal. Dan saya juga membutuhkan wadah untuk menerima tanggal yang dipilih untuk mengembalikannya ke aktivitas orang tua.

Untuk aktivitas kontainer, ini adalah deklarasi kelas:

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

Dan antarmuka untuk panggilan balik:

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

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

Callback adalah string karena tanggal adalah params dalam kueri pilih.

Kode untuk fragmen (berdasarkan fragmen tanggal awal):

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

}

Untuk membuat wadah + fragmen, saya menggunakan ViewPager (AppCompat) dengan kelas kustom yang memperluas FragmentPagerAdapter. Tidak ada dialog.

Pablo
sumber
2

Cukup Anda dapat menggunakan EventBus itu mudah dan berfungsi dengan baik

EventBus dalam 3 langkah

  1. Tentukan acara:

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

  2. Mempersiapkan pelanggan: Deklarasikan dan beri anotasi metode berlangganan Anda, tentukan secara spesifik mode utas:

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

Daftarkan dan batalkan registrasi pelanggan Anda. Misalnya di Android, aktivitas dan fragmen biasanya harus mendaftar sesuai dengan siklus hidupnya:

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

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
  1. Posting acara:

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

Sattar
sumber
1

Saya tahu ini mungkin terlambat. Tetapi saya juga selalu bingung dengan pertanyaan ini. Saya membagikan tautan ini ... karena ini mungkin penjelasan terbaik yang pernah saya temukan di web untuk ini. Ini memecahkan Fragmen ke Aktivitas & Fragmen ke Fragmen !

Dipecahkan & Dijelaskan dengan sangat baik

Aplikasi Yo
sumber
0

Ini bekerja untuk saya ..

dalam Aktivitas tambahkan metode ini

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

dan di Fragment tambahkan baris ini

((YourActivity)getContext).GetData("your data here");
Basant
sumber
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;
  }
}
Shweta Chandarana
sumber
-12

Cara sederhana lain untuk mendapatkan data, diteruskan dari aktivitas lain, dalam sebuah fragmen dalam aktivitas wadah: misalnya:

Activity_A => Activity_B (Fragmen)

Di Activity_A Anda, Anda membuat maksud seperti Anda mengirim data (String di sini) ke aktivitas lain:

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

di Fragmen Anda, terkandung dalam Activity_B Anda:

String data = getActivity().getIntent().getExtras();
SuperZouzou
sumber
getBaseContext()memberi saya kesalahan berikut:The method getBaseContext() is undefined for the type new View.OnClickListener(){}
Si8