0

I am learning how to use fragments, and in my MainActivity.java I have this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    A a = new A();

    B b = new B(a);

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new ContentFragment())
                .commit();
        ContentFragment frag = (ContentFragment) getSupportFragmentManager()
                .findFragmentById(R.id.container);
        frag.doInject(b);
    }
}

If I try to inject the dependency directly into the constructor of the fragment, Android Studio barks at me. So I'm trying this approach, but when debugging I get to where I am setting frag, and it's just null and is always null. So, I guess what I need to know is, in the simplest way possible, how do I call my doInject(b) and inject b into my fragment?

Another thing too, which I'm not sure about, is that later if I have a listener in the same MainActivity.java file, and I want to update the fragment with new content, I was hoping to do something like this:

@Override
public void handleResponseData(String s) {
    frag.updateTextbox(s);
}

But I have a feeling that I'm going to run into problems with that too. So I need some help understanding what it is that I'm trying to do. I've spent at least 5 hours trying to figure this out, and need some help, please!

Edit to show layout files:

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:ignore="MergeRootFrame" />

fragment_main.xml

<FrameLayout 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"
    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textbox"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World" />

</FrameLayout>
Brian Gottier
  • 4,522
  • 3
  • 21
  • 37

4 Answers4

0

If I try to inject the dependency directly into the constructor of the fragment

I'm not sure about that doInject method, but you should read Best practice for instantiating a new Android Fragment

For example,

ContentFragment frag = ContentFragment.newInstance(b);
getSupportFragmentManager().beginTransaction()
            .add(R.id.container, frag, "TAG")
            .commit();
// frag.doInject(b); // Can do, but not necessary

later if I have a listener in the same MainActivity.java file, and I want to update the fragment with new content, I was hoping to do something like this

Generally, this is not how you do that.

frag.updateTextbox(s);

I assume you have the Activity attached to the Fragment via a listener with a handleResponseData(String s), and you'd have to do

String s = "foo";
if (listener != null) {
    listener.handleResponseData(s);
}

therefore, instead of that, you only need do this

String s = "foo";
updateTextbox(s);
/*
if (listener != null) {
    listener.handleResponseData(s);
}
*/
Community
  • 1
  • 1
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • Actually, what I am listening for is an event, which in this case is either a network response, or a result from a db query. So I'm not attached to the fragment as a listener, but to the classes that are doing the background task. I am trying to use RxAndroid for that, but when RxAndroid is done, it calls a method that notifies the listeners. It's not really working though, so still just figuring it out. – Brian Gottier Aug 03 '16 at 16:32
  • Not sure about all that because nothing in your question seems to relate to RxAndroid / RxJava. Essentially, `.findFragmentById(R.id.container);` is returning null, right? You never added a Fragment to the container with that ID, so why do you expect anything else? – OneCricketeer Aug 03 '16 at 16:42
  • Thanks for helping me move past that issue. Now I'm on to other ones! – Brian Gottier Aug 03 '16 at 17:14
0

instead of new ContentFragment() . create the fragment and give a tag for that.

Sample Example :

if (savedInstanceState == null) {
            ContentFragment fragment = new ContentFragment();
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, fragment,"MyFragTag")
                    .commit();
            ContentFragment frag = (ContentFragment) getSupportFragmentManager()
                    .findFragmentByTag("MyFragTag");
            frag.doInject(b);
        }
0

(This is the most common way to do it) Imagine this is your fragment :

public class FactoryMethodFragment extends Fragment {
    public static final String ARG_MY_VALUE = "any value";

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Bundle arguments = getArguments();
        String myValue = "empty";

        if (arguments != null) {
            myValue = arguments
                    .getString(ARG_MY_VALUE);
        }

        Toast.makeText(getContext(), myValue,
                Toast.LENGTH_SHORT).show();

    }

    public static FactoryMethodFragment getInstance(String myValue){
        FactoryMethodFragment factoryMethodFragment 
                = new FactoryMethodFragment();

        Bundle arguments = new Bundle();
        arguments.putString(ARG_MY_VALUE, myValue);

        factoryMethodFragment.setArguments(arguments);

        return factoryMethodFragment;
    }
}

You have to create a factory method with arguments as shown in my example and use it like this :

getSupportFragmentManager().beginTransaction()
                .add(R.id.container,   FactoryMethodFragment.getInstance("myArgument"))
                .commit();

And for the comunication between fragment and activity normally we use an interface as the following :

public class FactoryMethodFragment extends Fragment {
    public static final String ARG_MY_VALUE = "any value";

    public interface CommunicationChannel {
        void onAction1(String argument);
        void onAction2(String argument);
    }

    private CommunicationChannel mCallback;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Bundle arguments = getArguments();
        String myValue = "empty";

        if (arguments != null) {
            myValue = arguments
                    .getString(ARG_MY_VALUE);
        }

        Toast.makeText(getContext(), myValue,
                Toast.LENGTH_SHORT).show();


        //Here we will send data to the activity
        mCallback.onAction1("data sent to activity");
        mCallback.onAction2("Another data sent to activity");

    }

    public static FactoryMethodFragment getInstance(String myValue){
        FactoryMethodFragment factoryMethodFragment
                = new FactoryMethodFragment();

        Bundle arguments = new Bundle();
        arguments.putString(ARG_MY_VALUE, myValue);

        factoryMethodFragment.setArguments(arguments);

        return factoryMethodFragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        if (context instanceof Activity) {
            mCallback = (CommunicationChannel) context;
        }
    }
}

And you implement it on your activity like this :

public class FatoryMethodActivity extends AppCompatActivity implements FactoryMethodFragment.CommunicationChannel {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.id.yourlayout);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container,   FactoryMethodFragment.getInstance("myArgument"))
                    .commit();
        }
    }

    @Override
    public void onAction1(String argument) {
        //HERE YOU GET DATA FROM YOUR FRAGMENT
    }

    @Override
    public void onAction2(String argument) {
        //HERE YOU GET DATA FROM YOUR FRAGMENT
    }
}
Juan Hurtado
  • 358
  • 1
  • 7
0

Thanks to everyone here I stumbled my way through this issue, and even though I've probably got some mistakes, I thought I'd post what I've got in case it might help somebody else.

In MainActivity.java:

if (findViewById(R.id.fragment_container) != null) {
    if (savedInstanceState == null) {
        frag = ContentFragment.getInstance(request);
        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container, frag).commit();
    }
}

In ContentFragment.java:

private PostRequest request;
private static ContentFragment myFragment = null;

public static ContentFragment getInstance(PostRequest request){
    if( myFragment == null ){
        myFragment = new ContentFragment();
        myFragment.request = request;
    }
    return myFragment;
}

I've only been working with Android/Java for about 10 days, and for me it's a lot to take in. Anyways, thanks for the help!

Brian Gottier
  • 4,522
  • 3
  • 21
  • 37