Android Fragment onClick 버튼 방법


91

내 onClick (View v) XML에서 메서드를 호출하려고하는데 Fragment에서 작동하지 않습니다. 이것은 오류입니다.

01-17 12:38:36.840: E/AndroidRuntime(4171): java.lang.IllegalStateException: 
Could not find a method insertIntoDb(View) in the activity class main.MainActivity 
for onClick handler on view class android.widget.Button with id 'btn_conferma'

자바 코드 :

public void insertIntoDb(View v) {
...
} 

XML :

<Button
        android:id="@id/btn_conferma"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0.0dip"
        android:layout_height="45dp"
        android:layout_marginLeft="2dp"
        android:layout_weight="1.0"
        android:background="@drawable/bottoni"
        android:gravity="center_horizontal|center_vertical"
        android:onClick="insertIntoDb"
        android:text="SALVA"
        android:textColor="#ffffff"
        android:textSize="16sp" />

1
더 많은 스택 트레이스 및 관련 코드를 게시하십시오
Emmanuel

2
여기 developer.android.com/guide/topics/ui/controls/… , "레이아웃을 호스팅하는 활동은 해당 메서드를 구현해야합니다."에 설명되어 있습니다. 귀하의 경우에는 조각에 해당 메서드를 구현했습니다. 이로 인해 활동에서 해당 메소드를 찾을 수 없기 때문에 IllegalStateException이 발생합니다. 아마도이 게시물에 표시된대로 트릭을 적용 할 수 있습니다. stackoverflow.com/a/6271637/2515815
hcelaloner

insertIntoDb (View) 메서드는 Fragment 클래스가 아닌 main.MainActivity에 있어야합니다.
betorcs


답변:


185

귀하의 활동에는

public void insertIntoDb(View v) {
...
} 

Fragment가 아닙니다.

위의 활동을 원하지 않는 경우. 프래그먼트에서 버튼을 초기화하고 리스너를 동일하게 설정하십시오.

<Button
    android:id="@+id/btn_conferma" // + missing

그때

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

   View view = inflater.inflate(R.layout.fragment_rssitem_detail,
    container, false);
   Button button = (Button) view.findViewById(R.id.btn_conferma);
   button.setOnClickListener(new OnClickListener()
   {
             @Override
             public void onClick(View v)
             {
                // do something
             } 
   }); 
   return view;
}

이로 인해 API 21을 사용하는 내 프로젝트에서 조각이 충돌합니다. 대체 수정 / 제안 사항이 있습니까?
Darth Coder

@DarthCoder 나는 그렇게 생각하지 않는다. 코드를 제시해야합니다. 그것은이 코드와 관련되지 않을 수는 여기에 게시
Raghunandan

@Sanu는 롤리팝 사전 롤리팝과 관련이 없습니다. 자세한 내용과 다른 질문을 게시 ..
Raghunandan

위의 답변으로 수행하면 클릭 이벤트가 트리거되지 않습니다.
Ted

4
위의 의견에 조금 놀랐습니다. 위법 행위는 아니지만 세부 사항을 게시하지 않고 "작동하지 않습니다"라고 말하는 것은 매우 비전문적입니다. 그리고 저에 관해서는 "그냥 작동합니다".
zzheng

15

또 다른 옵션은 조각이 View.OnClickListener를 구현하고 조각 내에서 onClick (View v)을 재정의하도록하는 것입니다. 프래그먼트가 활동과 대화해야하는 경우 원하는 메소드가있는 인터페이스를 추가하고 활동이 인터페이스를 구현하고 해당 메소드를 재정의하도록합니다.

public class FragName extends Fragment implements View.OnClickListener { 
    public FragmentCommunicator fComm;
    public ImageButton res1, res2;
    int c;

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

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            fComm = (FragmentCommunicator) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement FragmentCommunicator");
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        res1 = (ImageButton) getActivity().findViewById(R.id.responseButton1);
        res1.setOnClickListener(this);
        res2 = (ImageButton) getActivity().findViewById(R.id.responseButton2);
        res2.setOnClickListener(this);
    }
    public void onClick(final View v) { //check for what button is pressed
            switch (v.getId()) {
                case R.id.responseButton1:
                  c *= fComm.fragmentContactActivity(2);
                  break;
                case R.id.responseButton2:
                  c *= fComm.fragmentContactActivity(4);
                  break;
                default:
                  c *= fComm.fragmentContactActivity(100);
                  break;
    }
    public interface FragmentCommunicator{
        public int fragmentContactActivity(int b);
    }



public class MainActivity extends FragmentActivity implements FragName.FragmentCommunicator{
    int a = 10;
    //variable a is update by fragment. ex. use to change textview or whatever else you'd like.

    public int fragmentContactActivity(int b) {
        //update info on activity here
        a += b;
        return a;
    }
}

http://developer.android.com/training/basics/firstapp/starting-activity.html http://developer.android.com/training/basics/fragments/communicating.html


3
나는이 모든 시간을,하지만 여전히 추한 생각
알렉산더 파버

나도 처음에는했지만 이제는 거의 중고품이되었습니다. 게다가 실제로는 더 복잡한 앱에서 도움이되었지만 기본적으로는 과잉 인 것처럼 보입니다.
cjayem13

@ cjayem13, "이게 과잉 인 이유"를 자세히 설명해 주시겠습니까?
eRaisedToX

9

이것은 문제가 아니라 Android의 디자인입니다. 참조 여기 :

각 조각을 모듈 식의 재사용 가능한 활동 구성 요소로 디자인해야합니다. 즉, 각 프래그먼트는 자체 라이프 사이클 콜백을 사용하여 자체 레이아웃과 자체 동작을 정의하기 때문에 하나의 프래그먼트를 여러 활동에 포함 할 수 있으므로 재사용을 위해 설계하고 다른 프래그먼트에서 하나의 프래그먼트를 직접 조작하지 않아야합니다.

가능한 해결 방법은 MainActivity에서 다음과 같은 작업을 수행하는 것입니다.

Fragment someFragment;    

...onCreate etc instantiating your fragments

public void myClickMethod(View v){
    someFragment.myClickMethod(v);
}

그런 다음 Fragment 클래스에서 :

public void myClickMethod(View v){
    switch(v.getid()){
       // Your code here
    }
 } 

4

다른 사람들은 이미 onClick의 메소드가 조각이 아닌 활동에서 검색된다고 말했습니다. 당신이 정말로 그것을 원한다면 그럼에도 불구하고, 그것은 이다 가능합니다.

기본적으로 각 뷰에는 태그가 있습니다 (아마도 null). 루트 뷰의 태그를 해당 뷰를 확장 한 조각으로 설정했습니다. 그러면 뷰 부모를 쉽게 검색하고 클릭 한 버튼이 포함 된 조각을 검색 할 수 있습니다. 이제 메서드 이름을 찾고 리플렉션을 사용하여 검색된 조각에서 동일한 메서드를 호출합니다. 쉬운!

확장하는 클래스에서 Fragment:

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

    OnClickFragments.registerTagFragment(rootView, this); // <========== !!!!!

    return rootView;
}

public void onButtonSomething(View v) {
    Log.d("~~~","~~~ MyFragment.onButtonSomething");
    // whatever
}

모든 활동은 동일한 ButtonHandlingActivity에서 파생됩니다.

public class PageListActivity extends ButtonHandlingActivity

ButtonHandlingActivity.java :

public class ButtonHandlingActivity extends Activity {

    public void onButtonSomething(View v) {
        OnClickFragments.invokeFragmentButtonHandlerNoExc(v);
//or, if you want to handle exceptions:
//      try {
//          OnClickFragments.invokeFragmentButtonHandler(v);
//      } catch ...
    }

}

모든 xml onClick 핸들러에 대한 메소드를 정의해야합니다.

com / example / customandroid / OnClickFragments.java :

package com.example.customandroid;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Fragment;
import android.view.View;

public abstract class OnClickFragments {
    public static class FragmentHolder {
        Fragment fragment;
        public FragmentHolder(Fragment fragment) {
            this.fragment = fragment;
        }
    }
    public static Fragment getTagFragment(View view) {
        for (View v = view; v != null; v = (v.getParent() instanceof View) ? (View)v.getParent() : null) {
            Object tag = v.getTag();
            if (tag != null && tag instanceof FragmentHolder) {
                return ((FragmentHolder)tag).fragment;
            }
        }
        return null;
    }
    public static String getCallingMethodName(int callsAbove) {
        Exception e = new Exception();
        e.fillInStackTrace();
        String methodName = e.getStackTrace()[callsAbove+1].getMethodName();
        return methodName;
    }
    public static void invokeFragmentButtonHandler(View v, int callsAbove) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
        String methodName = getCallingMethodName(callsAbove+1);
        Fragment f = OnClickFragments.getTagFragment(v);
        Method m = f.getClass().getMethod(methodName, new Class[] { View.class });
        m.invoke(f, v);
    }
    public static void invokeFragmentButtonHandler(View v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
        invokeFragmentButtonHandler(v,1);
    }
    public static void invokeFragmentButtonHandlerNoExc(View v) {
        try {
            invokeFragmentButtonHandler(v,1);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    public static void registerTagFragment(View rootView, Fragment fragment) {
        rootView.setTag(new FragmentHolder(fragment));
    }
}

그리고 다음 모험은 proguard 난독 화가 될 것입니다 ...

추신

그것은 데이터가에 살고 있도록 응용 프로그램을 설계하는 당신에게 물론 최대입니다 모델 이 아닌 (있는 활동 조각에 컨트롤러 로부터 MVC , 모델 - 뷰 - 컨트롤러의 관점). 보기 는 XML을 통해 정의, 플러스 사용자 정의 뷰 클래스 (당신이 그들을 정의하면, 대부분의 사람들은 이미 무엇을 재사용) 것입니다. 경험 법칙 : 일부 데이터가 화면 회전 후에도 확실히 유지되어야하는 경우 모델에 속합니다 .


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

    View view = inflater.inflate(R.layout.writeqrcode_main, container, false);
    // Inflate the layout for this fragment

    txt_name = (TextView) view.findViewById(R.id.name);
    txt_usranme = (TextView) view.findViewById(R.id.surname);
    txt_number = (TextView) view.findViewById(R.id.number);
    txt_province = (TextView) view.findViewById(R.id.province);
    txt_write = (EditText) view.findViewById(R.id.editText_write);
    txt_show1 = (Button) view.findViewById(R.id.buttonShow1);

    txt_show1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e("Onclick","Onclick");

            txt_show1.setVisibility(View.INVISIBLE);
            txt_name.setVisibility(View.VISIBLE);
            txt_usranme.setVisibility(View.VISIBLE);
            txt_number.setVisibility(View.VISIBLE);
            txt_province.setVisibility(View.VISIBLE);
        }
    });
    return view;
}

괜찮아 !!!!


3
이것이 질문에 어떻게 대답하는지 설명해 주시겠습니까? 마지막 문장은 무엇을 의미합니까?
Teepeemm 2015

3

Kotlin 사용자의 경우 :

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?, 
    savedInstanceState: Bundle?) : View?
{
    // Inflate the layout for this fragment
    var myView = inflater.inflate(R.layout.fragment_home, container, false)
    var btn_test = myView.btn_test as Button
    btn_test.setOnClickListener {
        textView.text = "hunny home fragment"
    }

    return myView
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.