私は2つのクラスがあります。 1つはアクティビティ、もう1つは私がEditText
を持っているフラグメントです。アクティビティではasync-taskを持つサブクラスがあり、メソッドdoInBackground
ではいくつかの結果が出ます。それを変数に保存します。この変数をサブクラス "my activity"からこのフラグメントに送るにはどうすればいいですか?
Activityから、意図的にデータを送信します。
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
そしてフラグメントonCreateViewメソッドで:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("edttext");
return inflater.inflate(R.layout.fragment, container, false);
}
フラグメントからアクティビティデータにアクセスすることもできます。
活動:
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;
}
}
私はここに多くの答えを見つけました@ stackoverflow.comしかし確かにこれはの正しい答えです:
活動:
Bundle bundle = new Bundle();
String myMessage = "Stackoverflow is cool!";
bundle.putString("message", myMessage );
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) {
Bundle bundle = this.getArguments();
String myValue = bundle.getString("message");
...
...
...
}
あるいは単に
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
String myValue = this.getArguments().getString("message");
...
...
...
}
この答えは遅すぎるかもしれません。しかしそれは将来の読者には役に立つでしょう。
いくつかの基準があります。意図的にファイルを選ぶようにコーディングしました。さらなる処理のために特定のフラグメントに渡されるファイルを選択しました。私はファイルピッキングの機能を持つ多くのフラグメントを持っています。当時は、条件をチェックしてフラグメントを取得して値を渡すたびに、かなり嫌です。だから、私はインタフェースを使用して値を渡すことにしました。
ステップ1: Main Activityでインタフェースを作成します。
public interface SelectedBundle {
void onBundleSelect(Bundle bundle);
}
ステップ2: 同じアクティビティにメソッドを作成する
public void setOnBundleSelected(SelectedBundle selectedBundle) {
this.selectedBundle = selectedBundle;
}
ステップ3: 同じアクティビティにSelectedBundle参照を作成する
SelectedBundle selectedBundle;
ステップ4: すべてのフラグメントがファイルピッカー機能を必要とするSelectedBundle参照を初期化する必要があります。このコードをあなたのフラグメントonCreateView(..)
メソッドに配置してください。
((MainActivity)getActivity()).setOnBundleSelected(new MainActivity.SelectedBundle() {
@Override
public void onBundleSelect(Bundle bundle) {
updateList(bundle);
}
});
ステップ5:MainActivityから onActivityResultに、interfaceを使用して値をフラグメントに渡します。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
selectedBundle.onBundleSelect(bundle);
}
それで全部です。必要なすべてのフラグメントをFragmentClassに実装します。あなたは素晴らしいです。あなたはやった。ワオ...
Fragments(F)を使用する基本的なアイデアは、Androidアプリケーションで再利用可能な自立型のUIコンポーネントを作成することです。これらのフラグメントはアクティビティに含まれており、A - > FおよびF-Aからコミュニケーションパスを作成する一般的な(最善の)方法があります。フラグメントのみが分離されて自立するので、アクティビティを通してF-F間で通信する必要があります。
それでA - > Fからデータを渡すことはρяσερєяKによって説明されるのと同じことになるでしょう。その答えに加えて、Activityの中でFragmentsを作成した後に、Fragmentsでメソッドを呼び出すフラグメントにデータを渡すこともできます。
例えば:
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
articleFrag.updateArticleView(position);
最も便利で便利な方法は、フラグメントインスタンスを呼び出してその時点でデータを送信することです。 デフォルトではすべてのフラグメントにインスタンスメソッドがあります
たとえば、フラグメント名がMyFragmentの場合
だからあなたはこのような活動からあなたのフラグメントを呼び出すでしょう:
getSupportFragmentManager().beginTransaction().add(R.id.container, MyFragment.newInstance("data1","data2"),"MyFragment").commit();
* R.id.containerは私のFrameLayoutのIDです
だからMyFragment.newInstance( "data1"、 "data2")あなたはfragmentにデータを送ることができ、あなたの断片の中であなたはMyFragment newInstance(String param1、String param2)でこのデータを得ます
public static MyFragment newInstance(String param1, String param2) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
そして、フラグメントのonCreateメソッドでデータを取得します。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
だから今mParam1がdata1とmParam2がdata2
これで、フラグメント内でこのmParam1とmParam2を使用できます。
フラグメント(の具体的なサブクラス)への参照を非同期タスクに渡すと、そのフラグメントに直接アクセスできます。
フラグメント参照を非同期タスクに渡す方法はいくつかあります。
class FooTask extends AsyncTask
)である場合は、フラグメントをコンストラクタに渡します。ActivityからBundleを使用してデータを送信します。
Bundle bundle = new Bundle();
bundle.putString("data", "Data you want to send");
// Your fragment
MyFragment obj = new MyFragment();
obj.setArguments(bundle);
そしてフラグメントのonCreateViewメソッドでデータを取得します。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,`Bundle savedInstanceState)
{
String data = getArguments().getString("data");// data which sent from activity
return inflater.inflate(R.layout.myfragment, container, false);
}
非常に古い投稿ですが、それでも私は私に役立つはずだった小さな説明を追加することを敢えてします。
技術的には、アクティビティーからのフラグメントに任意のタイプのメンバーを直接設定できます。
では、なぜバンドルするのですか。
その理由は非常に単純です - Bundleは統一された処理方法を提供します。
- フラグメントを作成する/開く
- 再構成(画面の回転) - onSaveInstanceState()でoutStateに初期/更新されたバンドルを追加するだけです
- バックグラウンドでガベージコレクションされた後のアプリの復元(再構成の場合と同様)。
(実験が好きなら)単純な状況で回避策を作成することができますが、Bundleアプローチではバックスタック上の1つのフラグメントと1000の違いを見ることはできません。
だからこそ @Elenasys による答えが最も洗練された普遍的な解決策です。
そして、それが @Martin によって与えられる答えが 落とし穴を持つ理由
私がここで2つの最も支持された答えの間の違いが断片の異なる使い方によって与えられることを初心者に付け加えたいです。
渡すデータがあるJavaクラス内でフラグメントを使用する場合は、最初の回答を適用してデータを渡すことができます。
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
ただし、たとえばタブ付きフラグメントに対してAndroid Studioによって提供されているデフォルトコードを使用すると、このコードは機能しません。
デフォルトのPlaceholderFragmentをFragmentClassesに置き換えても、またFragmentPagerAdapterを新しい状況に修正してもgetItem()用のスイッチとgetPageTitle()用のスイッチを追加しても機能しません( here )。
警告:上記のクリップにはコードエラーがあります。これについては後で説明しますが、デフォルトのコードからタブ付きフラグメントの編集可能コードへの変更方法を確認するのに役立ちます。私の答えの残りの部分は、そのクリップのJavaクラスとxmlファイル(初心者のシナリオによるタブ付きフラグメントの最初の使用の代表)を考えた場合、はるかに理にかなっています。
このページで最も支持されている答えがうまくいかない主な理由は、タブ付きフラグメントのデフォルトコードでは、フラグメントが別のJavaクラスで使用されていることです。FragmentPagerAdapter!
そのため、データを送信するには、答え2を使用して、MotherActivityでバンドルを作成し、それをFragmentPagerAdapterに渡します。
それだけがまた間違っています。 ( たぶんあなたはそのようにそれをすることができました、しかしそれは本当に必要とされていない単なる複雑さです )。
そのための正しい/簡単な方法は、答え2を使って、問題のフラグメントにデータを直接渡すことです。はい。タブ付きフラグメントの場合、アクティビティとフラグメント(BUT)との間に密接な関係があります。 MotherActivity Javaクラスの中にタブ付きフラグメントを作成することをお勧めします(それらはMotherActivityの外部では使用されないため、サブクラスとして)。これは簡単で、MotherActivity Javaクラスの内部に必要なだけのフラグメントを追加するだけです。
public static class Tab1 extends Fragment {
public Tab1() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
return rootView;
}
}.
したがって、MotherActivityからそのようなフラグメントにデータを渡すには、MotherアクティビティのonCreateの上にプライベートなStrings/Bundlesを作成する必要があります。これには、フラグメントに渡したいデータを入力して、 onCreateの後に作成されたメソッド(ここではgetMyData()と呼びます)。
public class MotherActivity extends Activity {
private String out;
private Bundle results;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mother_activity);
// for example get a value from the previous activity
Intent intent = getIntent();
out = intent.getExtras().getString("Key");
}
public Bundle getMyData() {
Bundle hm = new Bundle();
hm.putString("val1",out);
return hm;
}
}
そしてフラグメントクラスでは、getMyDataを使用します。
public static class Tab1 extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public Tab1() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
TextView output = (TextView)rootView.findViewById(R.id.your_id_for_a_text_view_within_the_layout);
MotherActivity activity = (MotherActivity)getActivity();
Bundle results = activity.getMyData();
String value1 = results.getString("val1");
output.setText(value1);
return rootView;
}
}
データベースのクエリがある場合は、それらをMotherActivityで実行することをお勧めします(そして、上記のようにバンドル内のキーに添付された文字列/整数として結果を渡す)。構文がより複雑になります(これはgetActivityになります)。たとえば、getIntentはgetActivity()。getIntent)になりますが、必要に応じて実行することもできます。
私の初心者へのアドバイスは小さなステップに集中することです。まず、データを一切渡さずに、非常に単純なタブ付きアクティビティを開くようにします。動作しますか?それはあなたが期待するタブを開きますか?そうでない場合、なぜですか?
それから始めて、 このクリップ にあるような解決策を適用することによって、何が足りないのかを見てください。その特定のクリップでは、mainactivity.xmlは表示されません。それはきっとあなたを混乱させるでしょう。しかしあなたが注意を払うならば、あなたは例えばコンテキスト(tools:context)がxmlフラグメントファイルで間違っているのを見るでしょう。各フラグメントXMLは正しいフラグメントクラス(またはセパレータ$を使用したサブクラス)を指す必要があります。
また、メインアクティビティのJavaクラスで、tabLayout.setupWithViewPager(mViewPager)を追加する必要があることもわかります - TabLayout tabLayout =(TabLayout)findViewById(R.id.tabs);この行がないと、ビューは実際にはフラグメントのXMLファイルにリンクされていませんが、メインアクティビティのxmlファイルのみが表示されます。
メインアクティビティのJavaクラスの行に加えて、メインアクティビティのXMLファイルでは、状況に合わせてタブを変更する必要があります(たとえば、TabItemの追加または削除)。メインアクティビティXMLにタブがない場合は、最初に作成したときに正しいアクティビティタイプを選択しなかった可能性があります(新しいアクティビティ - タブ付きアクティビティ)。
最後の3段落で私はビデオについて話していることに注意してください。ですから、私がメインアクティビティXMLと言ったとき、それはビデオのメインアクティビティXMLです。あなたの状況では、それはMotherActivity XMLファイルです。
時々あなたはあなたの活動の中でIntentを受け取ることができます、そしてあなたはあなたの作業フラグメントに情報を渡す必要があります。
フラグメントを開始する必要がある場合でも回答は問題ないが、それでもまだ機能する場合は、setArguments()
はあまり役に立ちません。
渡された情報があなたのUIと対話する原因となる場合、別の問題が発生します。その場合は、myfragment.passData()
のようなものを呼び出すことはできません。Androidは、ビューを作成したスレッドだけが対話できるとすぐに伝えてしまうからです。
だから私の提案は受信機を使うことです。こうすることで、アクティビティを含め、どこからでもデータを送信できますが、作業はフラグメントのコンテキスト内で行われます。
あなたのフラグメントのonCreate()
:
protected DataReceiver dataReceiver;
public static final String REC_DATA = "REC_DATA";
@Override
public void onCreate(Bundle savedInstanceState) {
data Receiver = new DataReceiver();
intentFilter = new IntentFilter(REC_DATA);
getActivity().registerReceiver(dataReceiver, intentFilter);
}
private class DataReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int data= intent.getIntExtra("data", -1);
// Do anything including interact with your UI
}
}
あなたの活動の中で:
// somewhere
Intent retIntent = new Intent(RE_DATA);
retIntent.putExtra("data", myData);
sendBroadcast(retIntent);
アクティビティクラスからフラグメントにデータを送信するためのより良い方法は、セッターメソッドを介して渡すことです。好き
FragmentClass fragmentClass = new FragmentClass();
fragmentClass.setMyList(mylist);
fragmentClass.setMyString(myString);
fragmentClass.setMyMap(myMap);
そしてこれらのデータをクラスから簡単に取得します。
そのフラグメントの静的参照を取得してその関数にデータを渡し、同じメソッドの引数にそのデータを設定し、そのフラグメントのoncreateメソッドでgetArgumentを介してデータを取得し、そのデータをlocalに設定するpublic staticメソッドを作成することができます。変数.
activity
が初期化後にfragment
にアクションを実行させる必要がある場合、最も簡単な方法はactivity
にfragment
インスタンスのメソッドを呼び出させることです。 fragment
に、メソッドを追加します。
public class DemoFragment extends Fragment {
public void doSomething(String param) {
// do something in fragment
}
}
そしてactivity
で、fragment
マネージャーを使用してfragment
にアクセスし、method
を呼び出します。
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
fragmentDemo.doSomething("some param");
}
}
そしてactivity
は、このfragment
を呼び出すことによって、method
と直接通信できます。
以下のインタフェースを使ってアクティビティとフラグメントの間のコミュニケーションをとる
public interface BundleListener {
void update(Bundle bundle);
Bundle getBundle();
}
あるいは、インタフェースを使った双方向通信のためにこの一般的なリスナをたどって使用する
/**
* Created by Qamar4P on 10/11/2017.
*/
public interface GenericConnector<T,E> {
T getData();
void updateData(E data);
void connect(GenericConnector<T,E> connector);
}
フラグメントショーメソッド
public static void show(AppCompatActivity activity) {
CustomValueDialogFragment dialog = new CustomValueDialogFragment();
dialog.connector = (GenericConnector) activity;
dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
}
onAttach(Context)
でもGenericConnector
にコンテキストをキャストできます
あなたの活動に
CustomValueDialogFragment.show(this);
あなたのフラグメントで
...
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
connector.connect(new GenericConnector() {
@Override
public Object getData() {
return null;
}
@Override
public void updateData(Object data) {
}
@Override
public void connect(GenericConnector connector) {
}
});
}
...
public static void show(AppCompatActivity activity, GenericConnector connector) {
CustomValueDialogFragment dialog = new CustomValueDialogFragment();
dialog.connector = connector;
dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
}
注:"".toString().toString().toString();
のように使用しないでください。
私の解決策は、フラグメント内に静的メソッドを書くことです。
public TheFragment setData(TheData data) {
TheFragment tf = new TheFragment();
tf.data = data;
return tf;
}
こうすれば、私が必要とするすべてのデータは、それを処理するために必要となる可能性のある他の操作の前に、そのフラグメントの内部にあることが確実になります。私の考えではそれもきれいに見えます。
上記の方法のほとんどが機能する一方で、この質問に出くわしました。特に、コンポーネント(アクティビティまたはフラグメント)が作成されていないシナリオでは、 Event Bus Library を使用できることを追加したいと思います。これはAndroidのすべてのサイズに適していますプロジェクトと多くのユースケース。私は個人的にプレイストアで持っているいくつかのプロジェクトでそれを使用しました。
フラグメントとアクティビティの間でデータをやり取りするための最も賢い方法でテストされた方法は、変数を作成することです。
class StorageUtil {
public static ArrayList<Employee> employees;
}
次に、フラグメントからアクティビティにデータを渡すために、onActivityCreatedメソッドでこれを行います。
//a field created in the sending fragment
ArrayList<Employee> employees;
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
employees=new ArrayList();
//Java 7 and above syntax for arraylist else use employees=new ArrayList<Employee>() for Java 6 and below
//Adding first employee
Employee employee=new Employee("1","Andrew","Sam","1984-04-10","Male","Ghanaian");
employees.add(employee);
//Adding second employee
Employee employee=new Employee("1","Akuah","Morrison","1984-02-04","Female","Ghanaian");
employees.add(employee);
StorageUtil.employees=employees;
}
これで、どこからでもStorageUtil.employeesの値を入手できます。がんばろう!
最新のナビゲーションアーキテクチャコンポーネントを使用しているときに、私は同様の問題に遭遇しました。私の呼び出し元のアクティビティからFragmentにバンドルを渡すことで、上記のすべてのコードを試してみました。
Androidの最新の開発動向に従った最善の解決策は、View Model(Android Jetpackの一部)を使用することです。
親ActivityでViewModelクラスを作成して初期化します。このViewModelはアクティビティとフラグメントの間で共有する必要があります。
これで、フラグメントのonViewCreated()内で、同じViewModelを初期化し、ViewModelフィールドを監視するようにObserversを設定します。
必要に応じて、役に立つ、詳細なチュートリアルを紹介します。