How to update an XML TextView from other fragment - android

I have two fragments and I navigate by swiping between them. I want to update second fragment TextView from first fragment. Is it possibleto do that? Here's what I try to do but this doesn't worked to me.
public void updateOtherFragment(){
LayoutInflater inflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View vi = inflater.inflate(R.layout.fragment_log, null); //my second fragment xml file.
TextView tv = (TextView)vi.findViewById(R.id.textLog);
tv.setText("Updated from first fragment " + info.getName());
}

The default Google way for communication between fragments is to do that through the activity that hosts them.
The FirstFragment defines a callbacks interface that the activity must implement. When the activity gets a callback it can send the information through to the SecondFragment. Just read the example code below to make this more clear:
FirstFragment.java:
This fragment has a button, which when clicked sends a callback to its activity.
public class FirstFragment extends Fragment implements View.OnClickListener {
public FirstFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View result = inflater.inflate(R.layout.fragment_first, container, false);
result.findViewById(R.id.updateButton).setOnClickListener(this);
return result;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.updateButton:
((Callbacks) getActivity()).onUpdateLogtext("This is an update from FirstFragment");
break;
default:
throw new UnsupportedOperationException();
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof Callbacks))
throw new UnsupportedOperationException("Hosting activity must implement Callbacks interface");
}
public interface Callbacks {
void onUpdateLogtext(String text);
}
}
MainActivity.java:
This activity implements the FirstFragment.Callbacks interface in order to receive callbacks from FirstFragment. When it receives an onUpdateLogtext it just passes the data on to SecondFragment.
public class MainActivity extends AppCompatActivity implements FirstFragment.Callbacks {
private SecondFragment secondFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
secondFragment = (SecondFragment) getFragmentManager().findFragmentById(R.id.secondFragment);
}
#Override
public void onUpdateLogtext(String text) {
secondFragment.updateLogtext(text);
}
}
SecondFragment.java:
This just provides a public method that sets the textview with new data. And this method is used by MainActivity when it gets a onUpdateLogtext callback from FirstFragment.
public class SecondFragment extends Fragment {
private TextView tv;
public SecondFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View result = inflater.inflate(R.layout.fragment_second, container, false);
tv = (TextView) result.findViewById(R.id.textlog);
return result;
}
public void updateLogtext(String text) {
tv.setText(text);
}
}

Related

Unable to get a Fragment Object into MainActivity : android

I have created an experimental app in which I'm trying to learn to establish a successful communication b/w two fragments.
What I have is just one activity which is Main Activity. In this activity I have a view pager element in XML. I've created custom pager adapter which extends to Fragment Pager Adapter and two Fragments which are children and supplied by my pager adapter to the view pager.
What I'm trying to do is: FirstFragment has one button which on clicked changes the background color of the SecondFragment(there's a relative layout as parent), which will be visible on one swipe.
What I've done so far: I created an interface in FirstFragment, implemented in MainActivity, created a method in SecondFragment which changes the background color of layout and finally getting the SecondFragment in MainActivvity (at least trying to) and calling its method. But app is crashing on button click saying "Fragment SecondFragment not attached to a context"
Here's the code:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
MainActivity.java
package com.example.android.laboratory;
import...
public class MainActivity extends AppCompatActivity implements FirstFragment.MyListener {
ViewPager viewPager;
MyPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.view_pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
#Override
public void changeColor() {
SecondFragment secondFragment = new SecondFragment();
secondFragment.changeColor();
}
}
Custom Adapter:
package com.example.android.laboratory;
import ...
public class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
}
return null;
}
#Override
public int getCount() {
return 2;
}
}
First Fragment:
package com.example.android.laboratory;
import ...
public class FirstFragment extends Fragment {
MyListener listener;
public FirstFragment() {
// Required empty public constructor
}
#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);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.changeColor();
}
});
return view;
}
public interface MyListener{
void changeColor();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (MyListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString() + " must implement MyListener interface.");
}
}
}
Second Fragment:
package com.example.android.laboratory;
import ...
public class SecondFragment extends Fragment {
RelativeLayout relativeLayout;
public SecondFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
relativeLayout = view.findViewById(R.id.layout);
return view;
}
public void changeColor() {
relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorAccent));
}
}
Crash log:
12-23 12:18:03.574 31428-31428/com.example.android.laboratory E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.laboratory, PID: 31428
java.lang.IllegalStateException: Fragment SecondFragment{2bfa6ff2} not attached to a context.
at android.support.v4.app.Fragment.requireContext(Fragment.java:696)
at android.support.v4.app.Fragment.getResources(Fragment.java:760)
at com.example.android.laboratory.SecondFragment.changeColor(SecondFragment.java:32)
at com.example.android.laboratory.MainActivity.changeColor(MainActivity.java:28)
at com.example.android.laboratory.FirstFragment$1.onClick(FirstFragment.java:31)
at android.view.View.performClick(View.java:4791)
at android.view.View$PerformClick.run(View.java:19903)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5296)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)
You can see this doc https://developer.android.com/training/basics/fragments/communicating
If you want to make you own bicycle for some reasons, you could try something like this (observer pattern)
MyModel
import java.util.ArrayList;
public class MyModel {
private int color = R.color.colorPrimary;
private ArrayList<MyObserver> observers = new ArrayList<>();
interface MyObserver {
void setColor(int color);
}
public void setColor(int color) {
this.color = color;
for (int i = 0; i < observers.size(); i++) {
observers.get(i).setColor(color);
}
}
public void addObserver(MyObserver newObserver) {
if (observers.indexOf(newObserver) < 0) {
observers.add(newObserver);
}
}
public void deleteObserver(MyObserver oldObserver) {
if (observers.indexOf(oldObserver) > -1) {
observers.remove(oldObserver);
}
}
}
FirstFragment
public class FirstFragment extends Fragment {
#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);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.setColor(R.color.colorAccent);
}
});
return view;
}
}
SecondFragment
public class SecondFragment extends Fragment implements MyModel.MyObserver {
RelativeLayout relativeLayout;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
relativeLayout = view.findViewById(R.id.layout);
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.addObserver(this);
return view;
}
#Override
public void onDestroy() {
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.deleteObserver(this);
super.onDestroy();
}
#Override
public void setColor(int color) {
relativeLayout.setBackgroundColor(getResources().getColor(color, null));
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
ViewPager viewPager;
MyPagerAdapter adapter;
public MyModel myModel = new MyModel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.view_pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
}

how to make two fragments communicate each other inside viewpager in android

Suppose, I have two fragments , FragmentA and FragmentB inside viewpager .When i click the button in fragmentA then it should be able to add the textview in another fragmentB.so, how is it possible ....please help me out.
class Myadpter extends FragmentPagerAdapter {
Fragment fragment =null;
public Myadpter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if(position==0){
fragment = new Post();
}
if(position==1){
fragment = new ActiveChat();
}
if(position==2){
fragment = new LastUsers();
}
if(position==3){
fragment = new Noname();
}
return fragment;
}
#Override
public int getCount() {
return 4;
}
}
Implement a interface to communicate between two fragments, the class where the view pager is will be a middle man
As already stated by the other user, implementing an interface is the way to go. This link Communicating with Other Fragments will explain in more detail how to achieve what you are attempting to do. Hope this solves your problem.
Do as follows:
Fragment A
public class FragmentA extends Fragment implements View.OnClickListener {
OnButtonPressed mCallback;
Button yourButton;
TextView textViewFragA;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.your_layout, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
yourButton = findViewById(R.id.yourBtn);
textViewFragA = findViewById(R.id.textViewFragA);
yourButton.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch(view.getId()){
case R.id.yourBtn:
mCallback.onButtonPressed(textViewFragA);
break;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnButtonPressed) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString()
+ " must implement OnButtonPressed");
}
}
#Override
public void onDetach() {
mCallback = null; // Avoid memory leaking
super.onDetach();
}
/**
* Interface called whenever the user has clicked on the Button
* #param textView The TextView to add in FragmentB
*/
public interface OnButtonPressed{
void onButtonPressed(TextView textView);
}
}
FragmentB
public class FragmentB extends Fragment{
TextView textViewFragB;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.your_layout, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
textViewFragB= findViewById(R.id.textViewFragB);
}
public TextView getTextViewFragB(){
return textViewFragB;
}
Activity
public class TabControllerActivity extends AppCompatActivity implements FragmentA.OnButtonPressed{
MyAdapter adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity_layout);
// Your Stuff
}
// Everytime the user clicks on the Button in FragmentA, this interface method gets triggered
#Override
public void onButtonPressed(TextView textViewFragA) {
FragmentB fragmentB = (FragmentB) adapter.getItem(1)/* Be careful here and get the right fragment,
otherwise the App will crash*/
// Since you got the TextView and not only the text inside of it,
// you can do whatever you want. Here for example we set the text like the textViewFragA.
//In a few words you turn the textViewFragB to the other one
fragmentB.getTextViewFragB().setText(textViewFragA.getText().toString());
}
}
Hope it will help

how to pass Bitmap from Fragment to Activity?

strong textApp have a fragment that contains image and i want to pass the image to activity use Bitmap when i click to set this image as wallpaper.
From Fragment :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_view_pager, null);
ImageView resultView = (ImageView) view.findViewById(R.id.result_image);
resultView.setDrawingCacheEnabled(true);
bitmap = resultView.getDrawingCache();
resultView.setImageResource(pageNumber);
return view;
}
To Activity, when i click to set:
case R.id.setForce:
new TaskSetWallpaper(PreviewActivity.this).execute(bitmap);
break;
You can create an interface in your fragment, which the parent activity of the fragment is expected to implement. Then, you can cast the activity to the interface in onAttach() of the fragment and call methods in the interface to notify events or pass data to parent activity.
Fragment:
public class MyFragment extends Fragment {
private EventListener eventListener;
public interface EventListener() {
void onSetImage(Bitmap bitmap);
}
#Override
public void onAttach(Activity a) {
super.onAttach(a);
if (a instanceof EventListener) {
eventListener = (EventListener) a;
} else {
throw new UnsupportedOperationException("Parent activity should implement MyFragment.EventListener");
}
}
}
Parent activity:
public class ParentActivity extends AppCompatActivity implements MyFragment.EventListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
//---------
//---------
}
#Override
void onSetImage(Bitmap bitmap){
new TaskSetWallpaper(PreviewActivity.this).execute(bitmap);
}
}

How to communicate between fragments?

I am developing an Android application. I have a requirement like there is a button in fragment 1, when a user clicks that button result should be displayed in fragment 2. While loading the activity both fragments is attached. Here is my try:
In main activity:
public void dsp(String str) {
secondfragment f2=new secondfragment();
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
f2.setArguments(bundle);
}
In first fragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.fragone, container,false);
Button btn = (Button) v.findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
m.dsp("clicked");
}
});
return v;
}
In second fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.fragtwo, container,false);
tv= (TextView) v.findViewById(R.id.textView1);
tv.setText(this.getArguments().getString("name"));
return v;
}
When communicating from Fragment to Fragment you use an interface to pass data to the Activity which in turn updates the fragment you want to change.
For Example:
In Fragment 1:
public class FragmentOne extends Fragment{
public Callback mCallback;
public interface Callback{
void onUpdateFragmentTwo(String message);
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
mCallback = (Callback) activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.fragone, container,false);
Button btn = (Button) v.findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mCallback.onUpdateFragmentTwo("clicked");
}
});
return v;
}
}
then in main Activity implement the interface:
public class MainActivity extends AppCompatActivity implements Callback{
FragmentTwo fragmentTwo;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// ... Load views or perform logic
// ... Load Fragment Two into your container
if(savedInstanceState == null){
fragmentTwo = FragmentTwo.newInstance(new Bundle()); // use real bundle here
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_holder, fragmentTwo, "Frag2").commit();
}
}
// Interface method
#Override
public void onUpdateFragmentTwo(String message){
// Call activity method with the argument
if(fragmentTwo != null){
fragmentTwo.updateFragmentTwo(message);
}
}
}
Update
In your second fragment I typically use a static newInstance(Bundle args) method to initialize and then would use a public method to communicate from the Activity to the Fragment for example:
public class FragmentTwo extends Fragment{
public static FragmentTwo newInstance(Bundle args){
FragmentTwo fragment = new FragmentTwo();
fragment.setArguments(args);
return fragment;
}
//... Class overrides here onCreateView etc..
// declare this method
public void updateFragmentTwo(String updateText){
// .. do something with update text
}
}
Thats it, happy coding!
Here you have what the Android Documentation says about Communicating Between Fragments. Here you'll have all the necessary steps to make two or more fragments communicate securely :)

Refreshing a fragment from a DialogFragment

I've been going around in circles trying to do something that seems pretty basic. I have a DialogFragment that accepts a users input, then, on submission, refreshes a ListView in a Fragment that is part of a ViewPager.
I have everything working except the Fragment with the ListView does not refresh itself. It's a little confusing though, because it does refresh the data, but I have to swipe a couple views, then back again to see the updated data.
After doing some research, I'm supposed to use getItemPosition and notifyDataSetChanged on the ViewPager and it should work. The problem is that calling notifyDataSetChanged results in a Recursive entry to executePendingTransactions exception being thrown:
Main Activity
public class Main extends SherlockFragmentActivity implements MyListFragment.OnRefreshAdapterListener, DialogConfirmation.OnRefreshKeywordsListener //Updated Code
{
private static List<Fragment> fragments;
#Override
public void onCreate(final Bundle icicle)
{
setContentView(R.layout.main);
}
#Override
public void onResume()
{
mViewPager = (ViewPager)findViewById(R.id.viewpager);
fragments = new ArrayList<Fragment>();
fragments.add(new MyListFragment()); //fragment with the ListView
fragments.add(MyDetailFragment.newInstance(0));
fragments.add(MyDetailFragment.newInstance(1));
fragments.add(MyDetailFragment.newInstance(2));
mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mMyFragmentPagerAdapter);
}
private static class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
return fragments.get(index);
}
#Override
public int getCount() {
return 4;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
#Override
public void onRefreshAdapterListener() {
this.mMyFragmentPagerAdapter.notifyDataSetChanged();
}
//Updated Code
#Override
public void onRefreshTextListener() {
MyListFragment tf = (MyListFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentText);
if (tf == null)
tf = (MyListFragment)this.fragments.get(0);
tf.RefreshText();
}
}
ListFragment
public class MyListFragment extends SherlockListFragment
{
OnRefreshAdapterListener mRefreshAdapter;
#Override
public void onActivityCreated(Bundle savedState) {
adapter = new CustomAdapter();
/*code to add items to adapter */
this.setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (getArguments() != null && getArguments().getString("text").length() > 0)
{
SaveText(getArguments().getString("text"));
this.mRefreshAdapter.onRefreshAdapterListener(); //this line causes a "java.lang.IllegalStateException: Recursive entry to executePendingTransactions" exception
}
return inflater.inflate(R.layout.listing, container, false);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mRefreshAdapter = (OnRefreshAdapterListener)activity;
}
public interface OnRefreshAdapterListener {
public void onRefreshAdapterListener();
}
#Override
public void onDialogTextAdd(final String text) {
}
}
DialogFragment
public class DialogTextAdd extends DialogFragment implements OnEditorActionListener {
private EditText mText;
OnRefreshTextListener mTextKeywords; //Updated Code
public interface DialogTextAddListener {
void onDialogTextAdd(final String inputText);
}
public DialogTextAdd() {
// Empty constructor required for DialogFragment
}
//Updated Code
#Override
public void onAttach(Activity act) {
super.onAttach(act);
mTextKeywords = (OnRefreshTextListener)act;
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.dialog_edit, container);
mText = (EditText)view.findViewById(R.id.text_add);
getDialog().setTitle("Add Text");
// Show soft keyboard automatically
mText.requestFocus();
getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
mText.setOnEditorActionListener(this);
return view;
}
#Override
public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
if (EditorInfo.IME_ACTION_DONE == actionId) {
MyListFragment mf = new MyListFragment();
Bundle args = new Bundle();
args.putString("text", mText.getText().toString());
mf.setArguments(args);
//this seems to be intefering with the notifyDataSetChanged in the listing fragment
getActivity().getSupportFragmentManager().beginTransaction().add(mf, "my_fragment").commit();
mTextKeywords.onRefreshTextListener(); //Updated Code
this.dismiss();
return true;
}
return false;
}
}
I have everything working except the Fragment with the ListView does
not refresh itself.
There is no point on creating and adding to the FragmentActivity a new instance of MyListFragment. From your code it appears that you store the fragments that you use in a list so you have references to them(also, just out of curiosity, did you setup the fragments in portrait, did a rotation of the phone and retried to use the DialogFragment?). Having references to those fragment means you could always get them from the list and use them to call a refresh/update method.

Categories

Resources