user3453481
user3453481

Reputation: 51

Android Programming - Fragments and Listeners

I am following a tutorial on the internet and I have to make a listener for my buttons. The tutorial I am watching is very different from my code even though the video was posted not even a year ago. The video I am watching has no "fragment" code in it. In my code there is a fragment in my MainActivity.java. What is a fragment? In my mainactivity.java towards the end I get this:

public static class PlaceholderFragment extends Fragment {

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        button1 = (Button)rootView.findViewById(R.id.button1);
        button2 = (Button)rootView.findViewById(R.id.button2);
        button3 = (Button)rootView.findViewById(R.id.button3);

        button1.setOnClickListener(listener);
        button2.setOnClickListener(listener);
        button3.setOnClickListener(listener);

        return rootView;
    }
}

could anyone explain to me what a place holder fragment is? heres my code. I am getting an error here:

ERROR: "Toast.makeText(MainActivity.this, "toast", Toast.LENGTH_SHORT);"
Message: "No enclosing instance of the type MainActivity is accessible in scope"

. private static OnClickListener listener = new OnClickListener() { @Override public void onClick(View v) { int id = v.getId();

        switch(id)
        {
        case R.id.button1:
            Toast.makeText(MainActivity.this, "toast", Toast.LENGTH_SHORT);
            break;
        case R.id.button2:
            break;
        case R.id.button3:
            break;
        default:
            break;
        }
    }
};

HERES MY FULL CODE ( MainActivity.java ):

package com.example.androiddevelopmentonline_part2_1;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
import android.os.Build;

public class MainActivity extends ActionBarActivity {

private static Button button1, button2, button3;

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

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment())
                .commit();
    }
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}


private static OnClickListener listener = new OnClickListener()
{
    @Override
    public void onClick(View v) {
        int id = v.getId();

        switch(id)
        {
        case R.id.button1:
            Toast.makeText(MainActivity.this, "toast", Toast.LENGTH_SHORT);
            break;
        case R.id.button2:
            break;
        case R.id.button3:
            break;
        default:
            break;
        }
    }
};

/**
 * A placeholder fragment containing a simple view.
 */
public static class PlaceholderFragment extends Fragment {

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        button1 = (Button)rootView.findViewById(R.id.button1);
        button2 = (Button)rootView.findViewById(R.id.button2);
        button3 = (Button)rootView.findViewById(R.id.button3);

        button1.setOnClickListener(listener);
        button2.setOnClickListener(listener);
        button3.setOnClickListener(listener);

        return rootView;
    }
}
}

Upvotes: 0

Views: 1206

Answers (1)

Ani Fichadia
Ani Fichadia

Reputation: 277

Probably the best explanation is in the Developer Docs (here: https://developer.android.com/guide/components/fragments.html)

Here's something from the "QuickView"

Fragments decompose application functionality and UI into reusable modules
Add multiple fragments to a screen to avoid switching activities
Fragments have their own lifecycle, state, and back stack
Fragments require API Level 11 or greater

The way I paraphrase it, is that its a reusable component of the UI with it's own lifecycle. It is used to decompose your UI into (multiple), more self contained, and logical "sections".

In your case, I think your IDE has auto generated the code for you and generated the PlaceholderFragment. It is as it says, an autogenerated placeholder. You can get rid of it if you're only working with Activities for now. But its best to look up Fragment tutorials later as they are used quite frequently with newer versions of android (Fragments are not necessary, but they're sorta 'better practice', depending on your application architecture).

The reason you're getting an error with:

ERROR: "Toast.makeText(MainActivity.this, "toast", Toast.LENGTH_SHORT);"

Message: "No enclosing instance of the type MainActivity is accessible in scope"

is actually explained in the message. You've declared your OnClickListener into an anonymous, static, attribute. Because it is static, it cannot access the current instance of the class (it is "not in scope", it has no access to the non-static methods and attributes). To fix it, just remove the static keyword:

private OnClickListener listener = new OnClickListener() //... etc

For an explanation about the static keyword in Java, look here: http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html or What does the 'static' keyword do in a class?

EDIT (A neater way of implementing OnClickListener)

A better idea would be to put your OnClickListener within your PlaceholderFragment (since that's where it's used), or have your PlaceholderFragment implement View.OnClickListener (I prefer this way, less anonymous types, it code formats better, but its a matter of preference). An example (look for the comments):

// note, doesn't matter if it is static
// I got rid of the OnClickListener attribute and made PlaceholderFragment implement OnClickListener like so
public static class PlaceholderFragment extends Fragment implements OnClickListener
{
    // No need to provide a constructor. Fragments by default should have an empty constructor. If you want to add data to it, you need to create a "newInstance" method which calls fragment.setArguments (SomeBundleWithValuesInIt)
    @ Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState)
    {
        View rootView = inflater.inflate (R.layout.fragment_main, container, false);

        button1 = (Button) rootView.findViewById (R.id.button1);
        button2 = (Button) rootView.findViewById (R.id.button2);
        button3 = (Button) rootView.findViewById (R.id.button3);

        // I set the OnClickListener to the PlaceholderFragment itself, because it implements OnClickListener (which is an interface), you can use it this way.
        button1.setOnClickListener (this);
        button2.setOnClickListener (this);
        button3.setOnClickListener (this);

        return rootView;
    }

    // OnClickListener.onClick(View) moved here.
    @ Override
    public void onClick(View v)
    {
        int id = v.getId ();

        switch (id) {
            case R.id.button1 :
                // getActivity() can be used instead of Context (Activity is one of the subclasses of Context), but only within a Fragment in this case
                Toast.makeText (getActivity (), "toast", Toast.LENGTH_SHORT);
                break;
            case R.id.button2 :
                break;
            case R.id.button3 :
                break;
            default :
                break;
        }
    }
}

Upvotes: 3

Related Questions