简体   繁体   中英

How does an interface in Android Studio work?

So I read a lot about creating interfaces in an Android app but there is one way that I don't really understand. I will include my questions in the code, so you can see them directly. Please be gentle with me, I'm a beginner and really trying to understand it (sitting here for three hours on this one problem) but I just don't get it. :)

The construction is the following:

I have the MainActivity.java class and a MessageFragment.java class. So basically I have a fragment with a "Plain Text" View and a button. When the user inputs something in the text box and clicks the button, the input should be transmitted from the fragment to the MainActivity and it should be shown there on the screen. The MessageFragment.java looks like this (sorry for the long code, but I thought you might have to see everything):

package and import...

public class MessageFragment extends Fragment {

    private EditText editText;
    private Button button;
    OnMessageReadListener messageReadListener;

    public MessageFragment() {
    }

    public interface OnMessageReadListener{
        public void onMessageRead(String message);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_message, container, false);

        editText = view.findViewById(R.id.text_message);
        button = view.findViewById(R.id.bn);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String message = editText.getText().toString();
                messageReadListener.onMessageRead(message);

???QUESTION 1??? What is the last function doing? It looks to me that it calls the method
onMessageRead() but this method doesn't contain any activity in it's definition.

            }
        });

        return view;
    }

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

        Activity activity = (Activity) context;
        try{
            messageReadListener = (OnMessageReadListener) activity;
        }catch (ClassCastException e){
            throw new ClassCastException((activity.toString()+" must override OnMessageRead..."));
        }
    }

???QUESTION 2??? What is the whole onAttach method doing? I read things like "Called when 
a fragment is first attached to it's context" but I don't understand this. What is the context here?
And what does the line messageReadListener = (OnMessageReadListener) activity; do?
Also, why does this method come before the "onCreateView" method (it seemed like it while debugging)?

}

and the MainActivity.jave looks like this:

package and import...

public class MainActivity extends AppCompatActivity implements  MessageFragment.OnMessageReadListener{

    private TextView textView;

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

        if(findViewById(R.id.fragment_container) != null)
        {

            if (savedInstanceState != null){
                return;
            }

            MessageFragment messageFragment = new MessageFragment();
            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, messageFragment, null);
            fragmentTransaction.commit();
        }
    }

    @Override
    public void onMessageRead(String message) {

        textView = findViewById(R.id.txt_display_message);
        textView.setText(message);

    }

???QUESTION 3??? I really don't get it, when this last method onMessageRead() get's called here.
I know from debugging, that it get's called after I click the button in the fragment, but why?

}

EDIT: First of all, a huge thanks to you guys for your effort:) So, I think I got it a bit clearer but it would be nice, if someone could approve or disapprove the following:

Basically the onAttach() method is the link between the fragment and the activity. This method makes sure, that I have a variable in my fragment ( messageReadListener ) in which the MainActivity is "stored". So the onCreateView() method in the fragment gets processed after the onAttach() method. Thus, when the onClickListener in the fragment gets triggered, the line messageReadListener.onMessageRead(message); is basically saying MainActivity.onMessageRead(message); because the MainActivity is already "stored" in the variable messageReadListener . And this is also the reason why the method onMessageRead() in the MainActivity is triggered.

I still think that I have an error somewhere, because why wouldn't I just write this MainActivity.onMessageRead(message); immediately? And why don't I just define the onMessageRead() method directly in the MainActivity and get rids of the interface in the fragment?

I like your question and I am going to explain it to you in a simplified manner. Just like explaining to someone who has no idea about Java.

First thing first, a "class" is a blue print lets say for example you want to build a house. Firstly you need a plan to build the house, in Java a "class" is a plan and a finished product(which is a house in this case) is an "object". Going back to your code, "MainActivity" is what your user sees on the screen of the phone when opening the app, it is part of an interface. Let's say you built a news app for example. When the user open the news app, first thing that they see is normally 'news' which is your "MainActivity". And "extends" which will be for example 'World News'. What this means is that 'World News' is a continuation of "MainActivity" it is an inheritance. In real life I am sure you sometimes hear people say that you look like your mom or dad. Same thing that is happening here with "MainActivity" and "extends". "implements" is also a continuation of "MainActivity". The main reason for "implements" is that you want to build a more cleaner code.

"Override" in real world is the same as bypassing. In Java what this means is that "MainActivity" is still continuing but its inheritors are now customised, though they inherited their characteristics, properties or even behaviors from their main parent "MainActivity". They are now independent, same thing like the "news app". 'News', can have children 'World News', 'Motoring', 'Politics', 'Finance' and 'Weather'. All those are news, they inherited from 'News'. Some apps usually have more than one "MainActivity", depending on the size of the app. In simple terms an interface is the face of an application 'News App' in our example, that a user experiences while using the app. This is a more simplified explanation.

Here is a simple example:

@Override
 public void onClick(View v) {

 String enteredText;

 enteredText = mEditText.getText().toString();

 mTextView.setVisibility(View.VISIBLE);
 mTextView.setText(enteredText);

} });

You must create funtion setOnMessageReadListener in fragment and setup it in Activity

 public void setOnMessageReadListener(OnMessageReadListener messageReadListener){
    this.messageReadListener = messageReadListener;
}

QUESTION 1 - What is the last function doing? It looks to me that it calls the method onMessageRead() but this method doesn't contain any activity in it's definition .

The last function is the call to the method onMessageRead() your listener implements.

You have declared a variable with the type OnMessageReadListener, that is, it implements the method onMessageRead (String message).

OnMessageReadListener messageReadListener;

....

public interface OnMessageReadListener{
   public void onMessageRead(String message);
}

QUESTION 2 - What is the whole onAttach method doing? I read things like "Called when a fragment is first attached to it's context" but I don't understand this. What is the context here?

This is somewhat confusing but it boils down to the android activity life cycle .

The Android system, invokes some callbacks when the activity enters new states to allow developers to act on those state changes.

In this case, the Android system calls the OnAttach method when the fragment is attached to your Activity.

 Activity activity = (Activity) context;
 try{
     messageReadListener = (OnMessageReadListener) activity;
 }catch (ClassCastException e){
     throw new ClassCastException();
 }

As you see, what is happending here is the developer is telling Android "when you attach my fragment to the cointainer activity, set the messageReadListener variable to the Activity itself, that must implement the OnMessageReadListener interface or a ClassCastException will be thrown".

QUESTION 3 - I really don't get it, when this last method onMessageRead() get's called here.

It's called on your QUESTION 1 code.

  button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
          String message = editText.getText().toString();
          messageReadListener.onMessageRead(message);
    }
  });

So, What's going on here?

The developer is simply using interfaces to allow that fragment to send a message to the main activity when you click a button in your fragment.

Here you say "I got a variable that holds anything that implements the OnMessageReadListener interface".

Then on the main Activity you implement that interface by creating the method, onMessageRead().

When Adroid attaches the fragment to the main activity you assign that activity to your Fragment's variable messageReadListener , on the OnAttach callbak.

And after that, you just use that variable to call, at the OnClik button event, the onMessageRead() method on the main activity.

That allows your fragment and the main activity to comunicate untangled , that is without holding one, a reference to the other.

EDIT: QUESTION 4 I still think that I have an error somewhere, because why wouldn't I just write this MainActivity.onMessageRead(message); immediately? And why don't I just define the onMessageRead() method directly in the MainActivity and get rids of the interface in the fragment?

You can do that, but that would mean those classes get tangled . That is you need a reference to the MainActivity on your fragment.

With the interface, you can use your fragment on ANY activity. You just need it to implement the interface, on any new activity to use it.

So it is easier to reuse your code, and will be much cleaner to implement that interface on any activity you want your Fragment to be used, than to get an instance of each activity you want your Fragment to be used in, and check around what is the caller one.

To code to interfaces is considered a good practice on Object Oriented programming.

Jt's super easy, Escape if you don't need to know what is interface: interface is just like the name says, a class between two classes so they don't have to directly communicate each other Why? Because you may still don't know how exactly you want to handle the event that fired the interface function

Question 1: it doesn't need the activity inside it, the activity should implement this interface so when the user clicks the button, What ever this activity told the interface method to do will be executed

I'll stop here, i'll answer the rest if you understand the first one

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM