I have an activity "MainActivity" that contains two fragments. Fragment1 has a EditText and a button. When the user presses the button the text inside the EditText will be sent to Fragment2 which only has a TextView. But I can't quite figureout how to send the text from EditText in Fragment1 to TextView in Fragment2. If someone could help? Appreciated. Thanks
Fragment1
package org.pctechtips.myfragmentapp;
/**
* Created by george on 5/16/17.
*/
public class ButtonFragment extends Fragment {
Button bt;
EditText editText;
TextView txtView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.button_fragment,
container, false);
txtView = (TextView) view.findViewById(R.id.textView_fragment1);
editText = (EditText) view.findViewById(R.id.editText_fragment1);
bt = (Button) view.findViewById(R.id.button_fragment1);
bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
buttonClicked(v);
}
});
return view;
}
public void buttonClicked (View view) {
.onButtonClick(edittext.getText().toString());
}
}
MainActivity
package org.pctechtips.myfragmentapp;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*fragments 1 section*/
FragmentManager fm1 = getFragmentManager();
FragmentTransaction ft1 = fm1.beginTransaction();
ButtonFragment bf = new ButtonFragment();
ft1.add(R.id.button_fragment1, bf);
ft1.commit();
/*Fragment 2 section*/
FragmentManager fm2 = getFragmentManager();
FragmentTransaction ft2 = fm2.beginTransaction();
TextviewFragment tf = new TextviewFragment();
ft2.add(R.id.textView_fragment2, tf);
ft2.commit();
}
}
Fragment2
public class TextviewFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.text_fragment, container, false);
}
}
The quick and easy answer is to call getView().findViewById() from the activity (as shown below). The more proper approach is to give your fragments an interface that gets and retrieves the text. Below is the code for the quick and easy method, but when you create a fragment in Android studio it shows you how to do the more proper interface approach.
package org.pctechtips.myfragmentapp;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*fragments 1 section*/
FragmentManager fm1 = getFragmentManager();
FragmentTransaction ft1 = fm1.beginTransaction();
ButtonFragment bf = new ButtonFragment();
ft1.add(R.id.button_fragment1, bf);
ft1.commit();
/*Fragment 2 section*/
FragmentManager fm2 = getFragmentManager();
FragmentTransaction ft2 = fm2.beginTransaction();
TextviewFragment tf = new TextviewFragment();
ft2.add(R.id.textView_fragment2, tf);
ft2.commit();
EditText et = (EditText) ft1.getView().findViewById(YOUR_EDITTEXT_ID);
Button button = (Button) ft1.getView().findViewById(YOUR_BUTTON_ID);
TextView tv = (TextView) ft2.getView().findViewById(YOUR_TEXTVIEW_ID);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tv.setText(et.getText();)
}
});
}
You can do it by several ways. For example via Activity like in Official Docs. But, I'm prefer send broadcast messages via LocalBroadcastManager like in this answer of war_Hero:
In Sending Fragment(Fragment B - Your ButtonFragment)
public class FragmentB {
private void sendMessage() {
Intent intent = new Intent("custom-event-name");
intent.putExtra("message", "your message");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
And in the Message to be Received Fragment(FRAGMENT A - Your TextviewFragment)
public class FragmentA {
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Register receiver
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter("custom-event-name"));
}
// This will be called whenever an Intent with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
}
};
}
And don't forget to unregister receiver:
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
Related
My MainActivity contain buttons which is used to switch to different fragments. Inside each fragment there are also has buttons. Activity button onClickListener work fine before implementing button onClickListener in fragments. I wonder if this is not supported by Android or my code is not correct.
Any pointer is appreciated. Thank you.
Fragment code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
v = inflater.inflate(fragment1, container, false);
b2=(Button)v.findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v){
button2Clicked(v);
}
});
return inflater.inflate(R.layout.fragment1, container, false);
}
public void button2Clicked(View view){
//do something
}
Activity code:
public class MainActivity extends FragmentActivity {
private Button btnHealth;
private Button btnSetting;
private Button btnSleep;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Init component
btnHealth = (Button) findViewById(R.id.btnHealth);
btnSleep = (Button) findViewById(R.id.btnSleep);
btnSetting = (Button) findViewById(R.id.btnSetting);
replaceFragment(1);
btnHealth.setOnClickListener(new AdapterView.OnClickListener(){
#Override
//On click function
public void onClick(View view) {
replaceFragment(0);
}
});
btnSleep.setOnClickListener(new AdapterView.OnClickListener(){
#Override
//On click function
public void onClick(View view) {
replaceFragment(1);
}
});
btnSetting.setOnClickListener(new AdapterView.OnClickListener(){
#Override
//On click function
public void onClick(View view) {
replaceFragment(2);
}
});
}
//Create method replace fragment
private void replaceFragment(int pos) {
Fragment fragment = null;
switch (pos) {
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
case 2:
fragment = new Fragment3();
break;
default:
fragment = new Fragment2();
break;
}
if(null!=fragment) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_content, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
}
It is possible. If you want to handle the OnClick Event of the fragment inside the Activity class, you can do so by using FragmentInteractionListener (interface). Example: Android - handle fragment onClick from activity
frag1 calls frag 2 and frag 2 calls a method in frag1 that updates a textview. The code works (doesn't crash) but the frag1 UI (when I return from frag2) is not updated/
Is it a valid approach? Is there a way to update the UI?
here is the frag1 and frag2 code:
public class Frag1 extends android.app.Fragment {
private static TextView txt;
public Frag1() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = null;
rootview = inflater.inflate(R.layout.fragment_frag1, container, false);
return rootview;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
txt = (TextView) getActivity().findViewById(R.id.txt);
Button btn = (Button) getActivity().findViewById(R.id.btn1);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Frag2 f2 = new Frag2();
ft.replace(R.id.content_frame, f2);
ft.addToBackStack(null);
ft.commit();
}
});
}
void setTxt(String s){
txt.setText(s);
}
}
and frag2 - the setTxt() method updates the textview in frag1:
public class Frag2 extends Fragment {
private Button btn2;
public Frag2() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview;
rootview = inflater.inflate(R.layout.fragment_frag2, container, false);
Log.i("frag2","createdview");
return rootview;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Frag1 f1 = new Frag1();
f1.setTxt("msg from frag2");
btn2 = (Button) getActivity().findViewById(R.id.btn2);
btn2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Frag3 f3 = new Frag3();
ft.replace(R.id.content_frame, f3);
ft.addToBackStack(null);
ft.commit();
}
});
}
}
You can Broadcast Intent from the frag2
Intent intent = new Intent("key_to_identify_the_broadcast");
Bundle bundle = new Bundle();
bundle.putString("edttext", json.toString());
intent.putExtra("bundle_key_for_intent", bundle);
context.sendBroadcast(intent);
and then you can receive the bundle in your frag 1 by using the BroadcastReceiver class
private final BroadcastReceiver mHandleMessageReceiver = new
BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle =
intent.getExtras().getBundle("bundle_key_for_intent");
if(bundle!=null){
String edttext = bundle.getString("edttext");
}
//you can call any of your methods for using this bundle for your use case
}
};
in onCreateView() of your fragment you need to register the broadcast receiver first otherwise this broadcast receiver will not be triggered
IntentFilter filter = new IntentFilter("key_to_identify_the_broadcast");
getActivity().getApplicationContext().
registerReceiver(mHandleMessageReceiver, filter);
Finally you can unregister the receiver to avoid any exceptions
#Override
public void onDestroy() {
try {
getActivity().getApplicationContext().
unregisterReceiver(mHandleMessageReceiver);
} catch (Exception e) {
Log.e("UnRegister Error", "> " + e.getMessage());
}
super.onDestroy();
}
You can create separate broadcast receivers in all of your fragments and use the same broadcast to broadcast the data to all of your fragments. You can also use different keys for different fragments and then broadcast using particular key for particular fragment.
I have 2 Activity - MainActivity and MainActivity2 .
MainActivity has 2 fragments
MainActivity2 has 1 fragment
So i pass data from MainActivity_Frag_one to MainActivity_Frag_two.
When i click device back button and the blue button in MainActivity_Frag_two , it works well by going back to MainActivity_Frag_one.
After that, I pass data from MainActivity_Frag_two to MainActivity2_Frag_one using intent
When i click device back button it works well by going back to MainActivity_Frag_two but the blue button is not working (no effect when clicked, also no error shows).
May i know which part has gone wrong?
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
MainActivity_Frag_one MainActivity_Frag_one=new MainActivity_Frag_one();
transaction.add(R.id.activity_one_container,MainActivity_Frag_one);
transaction.commit();
}
MainActivity_Frag_one.java
public class MainActivity_Frag_one extends Fragment {
EditText get_text;
Button get_button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_activity__frag_one,container,false);
get_text=(EditText)rootView.findViewById(R.id.input_name);
get_button=(Button)rootView.findViewById(R.id.submit_button);
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
FragmentManager manager=getFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
Bundle bundle=new Bundle();
bundle.putString("message", get_text.getText().toString());
MainActivity_Frag_two fragobj=new MainActivity_Frag_two();
fragobj.setArguments(bundle);
transaction.replace(R.id.activity_one_container,fragobj);
transaction.addToBackStack("zzz");
transaction.commit();
}
});
return rootView;
}
}
MainActivity_Frag_two.java
public class MainActivity_Frag_two extends Fragment {
ImageView get_button;
Button get_to_second_activity;
String strtext;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_activity__frag_two,container,false);
TextView display_text=(TextView)rootView.findViewById(R.id.display_text);
strtext=getArguments().getString("message");
display_text.setText(strtext);
get_button=(ImageView)rootView.findViewById(R.id.back_button);
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getFragmentManager().popBackStack();
}
});
get_to_second_activity=(Button)rootView.findViewById(R.id.to_second_activity);
get_to_second_activity.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
Intent intent = new Intent(getActivity(),MainActivity2.class);
intent.putExtra("Check","data from mainactivity_frag_two is : "+strtext);
startActivity(intent);
FragmentManager manager=getFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.addToBackStack("");
transaction.commit();
}
});
return rootView;
}
}
MainActivity2.java
public class MainActivity2 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
MainActivity2_Frag_one MainActivity2_Frag_one=new MainActivity2_Frag_one();
transaction.add(R.id.activity_two_container,MainActivity2_Frag_one);
transaction.commit();
}
}
MainActivity2_Frag_one.java
public class MainActivity2_Frag_one extends Fragment {
TextView get_display;
ImageView get_button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_activity2__frag_one,container,false);
get_display=(TextView)rootView.findViewById(R.id.display);
String data1=getActivity().getIntent().getExtras().getString("Check");
get_display.setText(data1);
get_button=(ImageView)rootView.findViewById(R.id.back_to_previous_frag);
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getFragmentManager().popBackStack();
}
});
return rootView;
}
}
To go back to the previous activity you don't need to pop the fragment from the back stack. You can just call finish().
In your MainActivity2_Frag_one.java
Replace this :
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getFragmentManager().popBackStack();
}
});
with
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getActivity().finish();
}
});
The reason is popBackStack() can be used within the same activity.
I am trying to initialize a generic fragment in such manner that it can be used globally no matter what the instance of it is. For example:
public MainActivity extends Activity{
private Fragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first_layout);
FragmentManager fragManager = getFragmentManager();
FragmentTransaction transaction = fragManager.beginTransaction();
if(condition1){
fragment = new MyFirstFragment();
transaction
.add(R.id.registrationFragment, fragment); //registrationFragment is FrameLayout
transaction.commit();
}else if(condition2){
fragment = new MySecondFragment();
transaction
.add(R.id.registrationFragment, fragment); //registrationFragment is FrameLayout
transaction.commit();
}
//create intent filter
//create MyBroadcast object
//registerReceiver(receiverObject, intentFilter)
}
//Some action happens
class MyBroadcast extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(action1)) {
fragment.performAction();
}
}
}
public class MyFirstFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.fragment_holder_a, container, false);
//setWidgets etc...
// TODO Auto-generated method stub
return view;
}
//Used from main
public void performAction(String text){
//set some TextView's text from MainActivity event
//different from MySecondFragment performAction method
}
}
public class MySecondFragmentFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.fragment_holder_b, container, false);
//setWidgets etc...
// TODO Auto-generated method stub
return view;
}
//Used from main
public void performAction(String text){
//set some TextView's text from MainActivity event
//different from MyFirstFragment performAction method
}
}
The problem is that in my real application I may have more than 2 Fragments that the Fragment object could become an instance of. I am trying to avoid a lot of if statements to check which fragment instance was inflated with the FragmentManager. Also the problem I am facing is that When i declare the Fragment fragment = new MyFirstFragment(); I cannot access the fragment.performAction("Stringssss") method. This is not the solution I am looking for:
public MainActivity extends Activity{
private MyFirstFragment myFirstFrag;
private MySecondFragment mySecondFrag;
private MyThirdFragment myThirdFrag;
private MyNthFragment myNthFrag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first_layout);
FragmentManager fragManager = getFragmentManager();
FragmentTransaction transaction = fragManager.beginTransaction();
if(condition1){
myFirstFrag = new MyFirstFragment();
transaction
.add(R.id.registrationFragment, myFirstFrag); //registrationFragment is FrameLayout
transaction.commit();
}else if(condition2){
mySecondFrag = new MySecondFragment();
transaction
.add(R.id.registrationFragment, mySecondFrag); //registrationFragment is FrameLayout
transaction.commit();
}else if(condition3){
//...
}else if(conditionNth){
//...
}
//create intent filter
//create MyBroadcast object
//registerReceiver(receiverObject, intentFilter)
}
//Some action happens
class MyBroadcast extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(action1)) {
if(null != myFirstFrag)
myFirstFrag.performAction();
}else if(null != mySecondFrag){
mySecondFrag.performAction();
}else if(null != myThirdFrag){
myThirdFrag.performAction();
}else if(null != myNthFrag){
myNthFrag.performAction();
}
}else if(action.equals(actionNTH)){
if(null != myFirstFrag)
myFirstFrag.performAction();
}else if(null != mySecondFrag){
mySecondFrag.performAction();
}else if(null != myThirdFrag){
myThirdFrag.performAction();
}else if(null != myNthFrag){
myNthFrag.performAction();
}
}
}
}
As you can see in the BroadcastReceiver a lot of If-else statements start to pile up making the code clunky and dirty. I am looking for a clean solution that will not require me to have a bunch of if-else statements and keep the code simple.
Thank you.
I want to know how to stop running thread and asyncTask of fragment safely on android.
here is my code:
public class MainActivity extends FragmentActivity {
public Fragment mFragment;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
Button btn_next = (Button) findViewById(R.id.button_next);
btn_next.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((FragmentOne)mFragment).infoThread.interrupt();
}
});
Intent intent = getIntent();
String start_fragment = intent.getStringExtra("start_fragment");
onShowFragment(start_fragment);
}
public void onShowFragment(String select_fragment) {
Fragment fr = null;
switch (select_fragment) {
case "fragment1":
fr = new FragmentOne();
break;
case "gragment2":
fr = new FragmentTwo();
break;
}
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_place, fr);
ft.commit();
}
}
public class FragmentOne extends Fragment {
public Thread infoThread;
public View view_one;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view_one = inflater.inflate(R.layout.fragment_one, container, false);
onGetInfo();
return view_one;
}
public void onGetInfo() {
infoThread= new Thread(new Runnable() {
#Override
public void run() {
String response_info = HTTPUtils.HTTPPost(Global.USER_URL,
"name", "abc",
"password", "1234");
processGetInfo(response_info);
}
});
infoThread.start();
}
}
in here, when click btn_next button, FATAL EXCEPTION ERROR occur.
please help me.
try to use:
infoThread.stop()
instead of:
infoThread.interrupt();
You are never initialising mFragment with a value.
Add mFragment = fr; to onShowFragment
But, you're going to have a whole load of different issues if you carry on down this path. You should consider a more robust framework than performing http requests in threads spawned from a Fragment's onCreateView method.