OnFragmentInteractionListener를 구현하는 방법


151

android studio 0.8.2에서 탐색 창이있는 마법사 생성 앱이 있습니다.

조각을 만들고 newInstance ()로 추가 했는데이 오류가 발생합니다.

com.domain.myapp E / AndroidRuntime ﹕ 치명적 예외 : 기본 java.lang.ClassCastException : com.domain.myapp.MainActivity@422fb8f0은 OnFragmentInteractionListener를 구현해야합니다.

이 OnFragmentInteractionListener를 구현하는 방법을 찾을 수 없습니다 ?? 안드로이드 SDK 문서에서도 찾을 수 없습니다!

MainActivity.java

import android.app.Activity;

import android.app.ActionBar;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.widget.DrawerLayout;


public class MainActivity extends Activity
    implements NavigationDrawerFragment.NavigationDrawerCallbacks {

/**
 * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
 */
private NavigationDrawerFragment mNavigationDrawerFragment;

/**
 * Used to store the last screen title. For use in {@link #restoreActionBar()}.
 */
private CharSequence mTitle;

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

    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getFragmentManager().findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));
}

@Override
public void onNavigationDrawerItemSelected(int position) {
    // update the main content by replacing fragments
    FragmentManager fragmentManager = getFragmentManager();

    switch (position) {
        case 0: fragmentManager.beginTransaction()
                .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
                .commit(); break; 
        case 1: fragmentManager.beginTransaction() 
                .replace(R.id.container, AboutFragment.newInstance("test1", "test2"))
                .commit(); break; // this crashes the app
        case 2: fragmentManager.beginTransaction()
                .replace(R.id.container, BrowseQuotesFragment.newInstance("test1", "test2"))
                .commit(); break; // this crashes the app
    }
}


public void onSectionAttached(int number) {
    switch (number) {
        case 1:
            mTitle = getString(R.string.title_section1);
            break;
        case 2:
            mTitle = getString(R.string.title_section2);
            break;
        case 3:
            mTitle = getString(R.string.title_section3);
            break;
    }
}

public void restoreActionBar() {
    ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setTitle(mTitle);
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (!mNavigationDrawerFragment.isDrawerOpen()) {
        // Only show items in the action bar relevant to this screen
        // if the drawer is not showing. Otherwise, let the drawer
        // decide what to show in the action bar.
        getMenuInflater().inflate(R.menu.main, menu);
        restoreActionBar();
        return true;
    }
    return super.onCreateOptionsMenu(menu);
}

@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);
}

/**
 * A placeholder fragment containing a simple view.
 */
public static class PlaceholderFragment extends Fragment {
    /**
     * The fragment argument representing the section number for this
     * fragment.
     */
    private static final String ARG_SECTION_NUMBER = "section_number";

    /**
     * Returns a new instance of this fragment for the given section
     * number.
     */
    public static PlaceholderFragment newInstance(int sectionNumber) {
        PlaceholderFragment fragment = new PlaceholderFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_SECTION_NUMBER, sectionNumber);
        fragment.setArguments(args);
        return fragment;
    }

    public PlaceholderFragment() {
    }

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

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        ((MainActivity) activity).onSectionAttached(
                getArguments().getInt(ARG_SECTION_NUMBER));
    }
}

}

답변:


120

여기에 게시 된 답변은 도움이되지 않았지만 다음 링크는 도움이되었습니다.

http://developer.android.com/training/basics/fragments/communicating.html

인터페이스 정의

public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;

    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    ...
}

예를 들어, 조각에서 다음 메소드는 사용자가 목록 항목을 클릭 할 때 호출됩니다. 프래그먼트는 콜백 인터페이스를 사용하여 이벤트를 상위 활동에 전달합니다.

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    // Send the event to the host activity
    mCallback.onArticleSelected(position);
}

인터페이스 구현

예를 들어 다음 활동은 위 예제의 인터페이스를 구현합니다.

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...

    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article
    }
}

API 23 업데이트 : 2015 년 8 월 31 일

재정의 된 메소드 onAttach(Activity activity)는 이제에서 더 이상 사용되지 않습니다 android.app.Fragment. 코드를로 업그레이드해야합니다.onAttach(Context context)

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


@Override
public void onStart() {
    super.onStart();
    try {
        mListener = (OnFragmentInteractionListener) getActivity();
    } catch (ClassCastException e) {
        throw new ClassCastException(getActivity().toString()
                + " must implement OnFragmentInteractionListener");
    }
}

7
참고 onAttach(Activity activity);로 사용되지 및 교체onAttach(Context context)
EpicPandaForce

1
@EpicPandaForce 실제로 당신이 맞아, 나는 그것을 반영하기 위해 내 게시물을 업데이트
meda

1
onAttach에서 onStart로 이동하는 이유가 있습니까? 여전히 활동 대신 컨텍스트를 사용하여 onAttach에 넣을 수 있습니까?
Louis Tsai

난 그냥 사용 onAttach(context)하면 잘 작동 한다고 생각 합니다
EpicPandaForce

212

@meda 답변을 읽은 후에도 여전히 이해하지 못하는 사람들을 위해이 문제에 대한 간결하고 완전한 설명이 있습니다.

하자 당신이 두 조각이 말을 Fragment_A하고 Fragment_B있는 자동 생성 된 응용 프로그램에서 있습니다. 생성 된 프래그먼트의 맨 아래에 다음 코드가 있습니다.

public class Fragment_A extends Fragment {

    //rest of the code is omitted

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(Uri uri);
    }
}

public class Fragment_B extends Fragment {

    //rest of the code is omitted

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(Uri uri);
    }
}

이 문제를 극복하려면 onFragmentInteraction활동 에 메소드 를 추가해야합니다 MainActivity2. 그 후에 implements는 다음 MainActivity과 같은 모든 조각 이 필요합니다 .

public class MainActivity2 extends ActionBarActivity
        implements Fragment_A.OnFragmentInteractionListener, 
                   Fragment_B.OnFragmentInteractionListener, 
                   NavigationDrawerFragment.NavigationDrawerCallbacks {
    //rest code is omitted

    @Override
    public void onFragmentInteraction(Uri uri){
        //you can leave it empty
    }
}

추신 : 간단히 말해서이 방법은 조각 간 통신에 사용될 수 있습니다. 이 방법에 대해 더 알고 싶은 분은이 링크 를 참조하십시오 .


10
Android Studio에서 현재 버전의 SDK 를 사용하면 다른 답변에서는 언급되지 않은 메소드 를 구현 해야 합니다 onFragmentIntereactior(Uri). +1

2
대단히 감사합니다!
ofir_aghai

언급 해 주셔서 감사합니다. 많은 도움이되었습니다.
hablema

2
필요합니까? 리스너와 관련된 코드를 지울 수 있습니다. 다른 프래그먼트와 상호 작용할 필요가없는 프래그먼트가 있으면 해당 리스너는 쓸모가 없습니다.
추적

4
허용되는 답변보다 훨씬 쉽게 따르고 이해합니다.
jerrythebum

44

FragmentAndroid Studio에서 생성 한 자동 생성을 참조하십시오 . 새로운을 만들 때 FragmentStudio는 많은 코드를 스텁했습니다. 자동 생성 된 템플릿의 맨 아래에는 내부 인터페이스 정의가 OnFragmentInteractionListener있습니다. 귀하의 Activity요구는이 인터페이스를 구현합니다. 이것은 이벤트 Fragment를 알리기 위해 권장되는 패턴 Activity이므로 다른로드와 같은 적절한 조치를 취할 수 있습니다 Fragment. 세부 사항은이 페이지를 참조하고 "활동에 대한 이벤트 콜백 작성"섹션을 찾으십시오. http://developer.android.com/guide/components/fragments.html


문서에서는 프래그먼트 (이미 마법사에 의해 생성됨)에서 리스너를 구현하는 방법을 보여 주지만 앱이 중단되는 주요 활동에는 없습니다.
마리오 M

3
정확히. 문서 (및 생성 된 코드)는 인터페이스를 정의하고 Activity가에 연결 되면 인터페이스를 확인 합니다 Fragment. 충돌 Activity은 인터페이스를 구현하지 않았기 때문 입니다. 당신은 당신에 갈 필요 Activity하고 추가 implements YourFragment.OnFragmentInteractionListener한 다음 인터페이스에 정의 된 메소드의 구현을 추가 할 수 있습니다.
래리 Schiefer

좋아,하지만 난 그것을 안드로이드 SDK 설명서 어디에도 없기 때문에 그 구현을 추가하는 방법을 모른다
마리오 M에게

1
SDK의 일부는 아니지만 모범 사례입니다. 마법사가 생성 한 템플릿 코드는 기초를 마련해줍니다. 인터페이스 onFragmentInteraction(Uri uri)는 그저 스텁입니다. 이 메소드를 원하는대로 만들고 Activity구현해야 할 필요가 있습니다. 이것이 도움 되는지보십시오 .
Larry Schiefer

3
이 힌트는 많은 시간을 절약했습니다. 프래그먼트 UN을 생성하는 동안 "프래그먼트 팩토리 메소드 포함"및 "인터페이스 콜백 포함"을 체크하십시오. 그리고 OnFragmentInteractionListener를 구현할 필요가 없습니다. Java SDK 8과 함께 Android Studio 1.3.2를 사용하고 있습니다 .Android 6.0 (API 23) 및 sdk-platform 23입니다. 래리 수사 님 감사합니다.
학습자

28

이 페이지를 방문하는 사람들에게는이 오류에 대한 추가 설명이 필요합니다. 제 경우에는 조각을 호출하는 활동 이이 경우 2 개의 구현을 필요로했습니다.

public class MyActivity extends Activity implements 
    MyFragment.OnFragmentInteractionListener, 
    NavigationDrawerFragment.NaviationDrawerCallbacks {
    ...// rest of the code
}

9

조각에서 다음 코드를 제거해야합니다.

    try {
        mListener = (OnFragmentInteractionListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnFragmentInteractionListener");
    }

인터페이스 / 리스너는 활동 및 프래그먼트가보다 쉽게 ​​통신 할 수 있도록 기본적으로 작성됩니다.


2
대부분의 초보자 앱에서는이 리스너가 필요하지 않기 때문에 이것은 매우 좋은 점입니다.
코드 견습생

5

@ user26409021의 답변 외에도 ItemFragment를 추가 한 경우 ItemFragment의 메시지는 다음과 같습니다.

Activities containing this fragment MUST implement the {@link OnListFragmentInteractionListener} interface.

그리고 당신은 당신의 활동을 추가해야합니다;

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener, ItemFragment.OnListFragmentInteractionListener {

//the code is omitted

 public void onListFragmentInteraction(DummyContent.DummyItem uri){
    //you can leave it empty
}

더미 아이템은 ItemFragment의 맨 아래에있는 것입니다.


5

나와 함께이 코드를 삭제했습니다.

@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

다음과 같이 끝납니다 :

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

4

OnFragmentInteractionListener단편 대 활동 통신을 처리하기위한 기본 구현입니다. 필요에 따라 구현할 수 있습니다. 프래그먼트 내의 특정 작업 중에 액티비티에서 함수를 실행해야하는 경우이 콜백 메서드를 사용할 수 있습니다. 호스팅 activity과의 상호 작용이 필요하지 않은 fragment경우이 구현을 제거 할 수 있습니다.

간단히 말해서 이와 implement같은 조각 활동 상호 작용이 필요한 경우 조각 호스팅 활동의 리스너가 있어야 합니다.

public class MainActivity extends Activity implements 
YourFragment.OnFragmentInteractionListener {..}

조각은 다음과 같이 정의해야합니다.

public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}

또한 void onFragmentInteraction(Uri uri);활동에 대한 정의를 제공

또는 조각 활동 상호 작용이없는 경우 listener조각에서 초기화를 제거하십시오.onAttach


3

활동 대신 컨텍스트를 사용하십시오.

@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            mListener = (OnFragmentInteractionListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
}

3

부록 :

OnFragmentInteractionListener는 인터페이스 (OnFragmentInteractionListener)를 사용하여 Activity와 Fragment 간의 통신을 처리 하며 기본적으로 Android Studio에 의해 작성되지만 활동과 통신 할 필요가없는 경우이를 탈 수 있습니다.

목표는 프래그먼트를 여러 활동에 첨부하고 여전히 동일한 통신 방법을 재사용 할 수 있다는 것입니다 (모든 활동은 각 프래그먼트마다 고유 한 OnFragmentInteractionListener를 가질 수 있음).

그러나 내 조각이 한 가지 유형의 활동에만 첨부 될 것이라고 확신하면 해당 활동과 통신하고 싶습니다.

그런 다음 자세한 정보로 인해 OnFragmentInteractionListener를 사용하지 않으려면 다음을 사용하여 활동 메소드에 액세스 할 수 있습니다.

((MyActivityClass) getActivity()).someMethod()

이것이 대부분의 경우에 효과가 있지만 getActivity ()가 호출되는 동안 프래그먼트가 액티비티에서 분리 된 경우 (예 : asynctask의 postExecute 메소드에서 get 액티비티를 호출했지만 이미 프래그먼트를 떠난 경우) getActivity ()는 null을 반환 할 수 있습니다. asyncTask가 완료되기 전에 널 포인터 예외가 발생합니다. 따라서 안드로이드 문서 구체적 단편 상호 청취자 인터페이스 사용 말
MichaelStoddart

2

createview 메소드 대신 조각 활동으로 이동하여 모든 메소드를 제거하십시오.

조각은 oncreateview 메소드에만 있습니다.

//이 메소드 만 다른 메소드를 구현합니다.

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

레이아웃이 u 데모인지 확인하십시오.


감사합니다 ... 뭔가 필요한 경우 kalpeshnikam1080@gmail.com 드롭 메일
Kalpesh A. Nikam

1

프래그먼트가 활동에서 분리되거나 파괴 될 때 리스너의 파괴를 추가하고 싶습니다.

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

Context와 함께 새로운 onStart () 메소드를 사용할 때

@Override
public void onDestroy() {
    super.onDestroy();
    mListener = null;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.