Lesson 106. Android 3. Fragments. Interaction with Activity

Lesson 106. Android 3. Fragments. Interaction with Activity


In this lesson:

– Consider the interaction between Activity and its fragments

After placing the snippet, I would like to start interacting with it. That is, to place View components and work with them, refer to the snippets from Activity and vice versa. Let’s try to implement this.

For the purity of the experiment, we will work with two fragments: static and dynamic.

Let’s create a project:

Project name: P1061_FragmentActivity
Build Target: Android 4.1
Application name: FragmentActivity
Package name: ru.startandroid.develop.p1061fragmentactivity
Create Activity: MainActivity

IN strings.xml add rows:

Fragment 1
Fragment 2
Log
Find

We create layout and classes for two fragments.

fragment1.xml:



	
	
	

fragment2.xml:



	
	
	

Fragment1.java:

package ru.startandroid.develop.p1061fragmentactivity;

import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class Fragment1 extends Fragment {

  final String LOG_TAG = "myLogs";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment1, null);

    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        Log.d(LOG_TAG, "Button click in Fragment1");
      }
    });
    
    return v;
  }
}

In the snippet no the usual method for us findViewById to find components from the screen. So we call this method for ViewWhich will be the content of the snippet. In the method onCreateView we create a View and immediately find a button in it and put a handler on it. Then give the View system.

Fragment2.java:

package ru.startandroid.develop.p1061fragmentactivity;

import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class Fragment2 extends Fragment {

  final String LOG_TAG = "myLogs";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment2, null);
    
    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        Log.d(LOG_TAG, "Button click in Fragment2");
      }
    });
    
    return v;
  }
}

Everything is similar to Fragment1.

We configure the main Activity.

main.xml:



	
	
	
	
	

Button, component fragment into which Fragment1 is placed, and a FrameLayout container into which we then place Fragment2.

Notice the attribute tools: layout. It lists the layout file and we can see at the development stage what the static snippet will look like when the application is launched.

To do this, right-click on the component fragment, and through the item Fragment Layout specify the desired layout.

MainActivity.java:

package ru.startandroid.develop.p1061fragmentactivity;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Fragment frag2 = new Fragment2();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(R.id.fragment2, frag2);
        ft.commit();
    }
}

Here we just add Fragment2 to the container.

We save everything, launch the application.

press the button Log in the first fragment and look log:

Button click in Fragment1

press Log in the second snippet:

Button click in Fragment2

Everything is O.K. The components in the snippets were found and the handlers responded to clicks.

The onClick attribute we used to use for a button does not roll here. The method specified in this attribute will be called in Activity, not in a snippet.

Access a snippet from Activity

Let’s figure out how to access the snippet from Activity. To do this, FragmentManager has a findFragmentById method that accepts the fragment component id (if the fragment is static) or the container id (if dynamic) as input.

We have in main.xml there is a button btnFindThe calling method onClick when pressed. home in MainActivity.java method onClick:

  public void onClick(View v) {
    Fragment frag1 = getFragmentManager().findFragmentById(R.id.fragment1);
    ((TextView) frag1.getView().findViewById(R.id.textView))
        .setText("Access to Fragment 1 from Activity");

    Fragment frag2 = getFragmentManager().findFragmentById(R.id.fragment2);
    ((TextView) frag2.getView().findViewById(R.id.textView))
        .setText("Access to Fragment 2 from Activity");
  }

we use the method findFragmentById. In the first case, the input is passed the component id of the fragmentBecause Fragment1 is located in this way. When searching for Fragment2 we specify container idIn which this snippet was placed. As a result, the findFragmentById method returns a Fragment object to us.

Next, we access the View using the getView method, find the TextView in it, and modify the text.

We save everything, run it. press the button Find

The texts in the snippets have been updated. Thus, with Activity, we came across fragments and their components.

Just in case I’ll say one thing in the category “Thank you kep!”. If you look at the MainActivity code, you can see that working with frag2 in the onCreate method and with frag2 in the onClick method, we work with the current Fragment2 fragment. It is. Both frag2s will eventually be referenced by one object. So if you dynamically added a snippet, you already have a link to it, and you no longer need to search for it through findFragmentById.

Access the Activity from the snippet

Now let’s try to work with the snippet on Activity. To do this, the snippet has the getActivity method.

Let’s rewrite the button handler in the first snippet. Let’s change the text of the button btnFind.

Fragment1.java:

package ru.startandroid.develop.p1061fragmentactivity;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class Fragment1 extends Fragment {

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment1, null);
    
    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        ((Button)getActivity().findViewById(R.id.btnFind)).setText("Access from Fragment1");
      }
    });
    
    return v;
  }
}

We get Activity by the getActivity method, look for the button in it and change the text.

Save, run. Click the button in the first snippet:

Works. From the snippet we replaced the Activity component.

Snippet event handling in Activity

Consider the mechanism described in the help: the snippet generates an event and puts the Activity handler.

For example, Activity has two snippets. The first is a list of article headings. Second – displays the content of the article selected in the first. We click on the title of the article in the first snippet and get the content in the second. In this case, the purpose of the first snippet is to pass to Activity the information that the title is selected. And Activity is already deciding what to do with this information. For example, if the application is running on a flatbed tablet, you can display the content of the article in the second snippet. If the application is running on a smartphone, the screen is small for two snippets and you need to run a separate Activity with the second snippet to display the article.

The trick here is that the first snippet is not interesting for all these tormenting Activity. Fragment is a detached module. His job is to inform that the selected article is something like that. He doesn’t have to look for the second snippet and work with it – that’s the Activity.

Here is a little distracted by a small lyrical digression. Modularity, in general, is a very important and useful thing. And it should be used for versatility, convenience and ease in understanding the operation of their applications. But of course there are no unique recipes for how to organize everything properly. Everyone does their own thing. It is for these reasons that I give purely technical things to my lessons individual components and I do not tell you how to organize and write whole application. Otherwise, the forum would already be broken from the message that I do everything wrong and should be different, and everyone would share their vision. And there would be a bunch of disputes where one side says that the crocodile is green, and the other side says that the nymph is not green but long))

Let’s return to the lesson. The snippet should tell the Activity that the article is selected. To do this, it will call some method in Activity. And as help tells us, the best way here is to use the interface that we describe in the snippet and which will then be implemented in Activity. The scheme is known and common. Let’s implement. There are no articles in our application, so we will just pass an arbitrary string from the second snippet to Activity. And Activity will already display this line in the first snippet.

rewrite Fragment2.java:

package ru.startandroid.develop.p1061fragmentactivity;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class Fragment2 extends Fragment {
  
  public interface onSomeEventListener {
    public void someEvent(String s);
  }
  
  onSomeEventListener someEventListener;
  
  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
        try {
          someEventListener = (onSomeEventListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement onSomeEventListener");
        }
  }

  final String LOG_TAG = "myLogs";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment2, null);
    
    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        someEventListener.someEvent("Test text to Fragment1");
      }
    });
    
    return v;
  }
}

describe the interface onSomeEventListener. It has a method someEventThat receives a string at the input. This interface will implement Activity.

In the method onAttach we get the Activity to which the snippet is attached. We are trying to bring this Activity to the onSomeEventListener interface type so that someEvent method can be called and a string is passed there. Now someEventListener is referencing Activity.

Next, the village onCreateView, In the button handler, we call someEvent and send the text there. This method will be practiced in Activity.

Now we change Activity.

MainActivity.java:

package ru.startandroid.develop.p1061fragmentactivity;

import ru.startandroid.develop.p1061fragmentactivity.Fragment2.onSomeEventListener;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity implements onSomeEventListener{

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Fragment frag2 = new Fragment2();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(R.id.fragment2, frag2);
        ft.commit();
    }

  @Override
  public void someEvent(String s) {
      Fragment frag1 = getFragmentManager().findFragmentById(R.id.fragment1);
      ((TextView)frag1.getView().findViewById(R.id.textView)).setText("Text from Fragment 2:" + s);
  }
}

add the interface onSomeEventListener to the class description.

onCreate unchanged.

We implement the method someEvent. We just look for the first snippet and insert the text there.

We save and run everything. Click the button in the second snippet:

The second snippet passed a line through Activity to the interface, and it found the first snippet and displayed that string there.

In the next lesson:

– place items in ActionBar




Discuss in the forum [66 replies]

Leave a Comment