เรียกวิธีการกิจกรรมจากส่วน


318

พยายามที่จะเรียกวิธีการในกิจกรรมของฉันจากส่วน ฉันต้องการแฟรกเมนต์เพื่อให้ข้อมูลเมธอดและรับข้อมูลเมื่อเมธอดส่งคืน ฉันต้องการบรรลุคล้ายกับการเรียกใช้วิธีการคงที่ แต่ไม่มีการใช้คงที่เพราะมันสร้างปัญหาในกิจกรรม

ใหม่สำหรับชิ้นส่วนดังนั้นฉันต้องการคำอธิบายที่ง่ายและสอนได้!

ขอบคุณ!

คำตอบ:


820

จากส่วนถึง activty:

((YourActivityClassName)getActivity()).yourPublicMethod();

จากกิจกรรมเป็นชิ้นส่วน:

FragmentManager fm = getSupportFragmentManager();

//if you added fragment via layout xml
YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentById(R.id.your_fragment_id);
fragment.yourPublicMethod();

หากคุณเพิ่มแฟรกเมนต์ผ่านโค้ดและใช้tagสตริงเมื่อคุณเพิ่มแฟรกเมนต์ของคุณให้ใช้findFragmentByTagแทน:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");

5
ระวังสาเหตุที่ไม่คาดคิดเกิดขึ้นถ้านักแสดงไม่ทำงาน .. : S
Ewoks

48
เพื่อหลีกเลี่ยงการใช้ปัญหานักแสดง: Activity act = getActivity (); ถ้า (ทำหน้าที่อินสแตนซ์ของ YourActivityClassName) ((YourActivityClassName) ทำหน้าที่). YourPublicMethod (); }
ericharlow

@ ริชาร์ด: เราจะทำสิ่งที่ตรงกันข้ามได้อย่างไรเช่นถ้าเราต้องทำวิธีส่วนย่อยในกิจกรรม?
Himanshu

5
การออกแบบไม่ดีและไม่ปลอดภัยในการสร้างกิจกรรม ส่วนไม่ จำกัด เฉพาะกิจกรรมที่เฉพาะเจาะจง
Aviv Ben Shabat

3
@ Kay ไม่จำเป็นต้อง แฟรกเมนต์สามารถใช้เป็น "แฟรกเมนต์" ของกิจกรรมขนาดใหญ่ใด ๆ ที่แยกออกจากกัน เพื่อสร้าง UIs ที่ตอบสนองได้เช่น ฉันไม่ค่อยใช้แฟรกเมนต์เดียวกันและแนบกับโฮสต์กิจกรรมอื่น
ริชาร์ด

201

คุณควรพยายามแยกชิ้นส่วนออกจากกิจกรรมในกรณีที่คุณต้องการใช้งานที่อื่น คุณสามารถทำได้โดยการสร้างอินเทอร์เฟซที่กิจกรรมของคุณดำเนินการ

ดังนั้นคุณจะกำหนดอินเทอร์เฟซดังต่อไปนี้:

ตัวอย่างเช่นคุณต้องการให้สตริงเป็นกิจกรรมและให้มันคืนค่าจำนวนเต็ม:

public interface MyStringListener{
    public Integer computeSomething(String myString);
}

สามารถกำหนดได้ในส่วนหรือไฟล์แยกต่างหาก

จากนั้นคุณจะให้กิจกรรมของคุณใช้อินเทอร์เฟซ

public class MyActivity extends FragmentActivity implements MyStringListener{

  @Override
  public Integer computeSomething(String myString){
   /** Do something with the string and return your Integer instead of 0 **/ 
   return 0;
  }

}

จากนั้นในแฟรกเมนต์ของคุณคุณจะมีตัวแปร MyStringListener และคุณจะตั้งค่าผู้ฟังในเมธอดแฟรกเมนต์ onAttach (กิจกรรมกิจกรรม)

public class MyFragment {

        private MyStringListener listener;

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            try {
                listener = (MyStringListener) context;
            } catch (ClassCastException castException) {
                /** The activity does not implement the listener. */
            }
        }

    }

แก้ไข (2015/12/17):onAttach(Activity activity) is deprecated, use onAttach(Context context) instead, it works as intended

คำตอบแรกใช้งานได้จริง แต่มันจะแสดงชิ้นส่วนปัจจุบันของคุณกับกิจกรรมโฮสต์ วิธีปฏิบัติที่ดีในการป้องกันไม่ให้แฟรกเมนต์แยกออกจากกิจกรรมโฮสต์ในกรณีที่คุณต้องการใช้มันในระดับความรุนแรงอื่น


58
สำหรับคนอื่นที่มองสิ่งนี้ในขณะที่คำตอบที่ได้รับการยอมรับนั้นทำงานได้ดีนี่เป็นวิธีที่ดีกว่าและปลอดภัยกว่าจากมุมมองของการออกแบบ
Paul Richter

7
คำตอบนี้ดีขึ้นมากในแง่ของการออกแบบรหัส และมันจะไม่ทำให้เกิดปัญหาถ้ากิจกรรมนั้นผิดพลาด
เดวิดที

3
+1 แต่ฉันจะไม่ใช้ try-catch ใน theAttach ปล่อยให้มันล้มเหลว หากผู้ฟังเป็นทางเลือก (นั่นคือการล้มเหลวไม่เหมาะสม) ให้เพิ่มเมธอด set / addListener ให้กับแฟรกเมนต์
ataulm

สำหรับการสื่อสารด้านตรงข้ามโปรดดูที่: developer.android.com/training/basics/fragments/... การใช้อินเทอร์เฟซของแฟรกเมนต์ (ซึ่งเป็นวิธีที่ปลอดภัยในการทำแฟรกเมนต์ -> กิจกรรม comm ตามที่อธิบายไว้ข้างต้น) คุณสามารถเรียกวิธีการที่อยู่ในแฟรกเมนต์ของคุณจากกิจกรรมได้เช่นกันหากคุณต้องการดำเนินการตามกิจกรรม การสื่อสาร
Kerem

แฟรกเมนต์หมายถึงการนำมาใช้ซ้ำและตั้งค่าในกิจกรรมใด ๆ ถ้าฉันมี 5 กิจกรรมที่ใช้แฟรกเมนต์เดียวกัน คำตอบของมาร์โกคือคำตอบที่ถูกต้องและเป็นแนวปฏิบัติที่ดีสำหรับการสื่อสารระหว่างส่วนและส่วนย่อยของกิจกรรม
blockwala

51

สำหรับนักพัฒนาKotlin

(activity as YourActivityClassName).methodName()

สำหรับนักพัฒนาJava

((YourActivityClassName) getActivity()).methodName();

มันทำให้เกิดข้อผิดพลาดใน kotlin ถ้าเราใช้รหัสนี้ .. มีวิธีอื่นไหม
Jake Garbo

1
เมื่อฉันวิ่ง ฉันได้รับค่า null ของ ActivityClass ฉันคิดว่านี่ไม่ใช่วิธีที่เหมาะสมใน kotlin แม้ว่าจะไม่มีข้อผิดพลาดก็ตาม หรืออาจเป็นข้อบกพร่อง?
Jake Garbo

@ JakeGarbo มันเป็นวิธีที่เหมาะสมอย่างอื่น 12 คนยังไม่ได้ลงคะแนน สิ่งที่สองบางครั้งgetActivity ()ผลตอบแทน null ตรวจสอบคำถามเหล่านั้นใน SO
Wasim K. Memon

@ JakeGarbo Ya พวกเขาบอกคุณ ถ้ามันใช้ได้ผลกับคุณก็ควรจะชื่นชมหรือหาวิธีอื่นหรือเรียนรู้วิธีการเขียนโค้ดก่อน
Wasim K. Memon

13

อัปเดตหลังจากฉันเข้าใจมากขึ้นว่าชิ้นส่วนทำงานอย่างไร แต่ละส่วนเป็นกิจกรรมของผู้ปกครอง ดังนั้นเพียงใช้:

getActivity().whatever

จากภายในชิ้นส่วน มันเป็นคำตอบที่ดีกว่าเพราะคุณหลีกเลี่ยงการปลดเปลื้องมาก หากคุณไม่สามารถหลีกเลี่ยงการปลดเปลื้องด้วยวิธีนี้ใช้หนึ่งด้านล่าง

============

สิ่งที่คุณต้องทำคือทำกิจกรรมภายนอก

((MainActivity) getActivity()).Method();

การสร้างอินสแตนซ์ใหม่จะทำให้เฟรมของ Android สับสนและจะไม่สามารถจดจำได้ ดูสิ่งนี้ด้วย :

https://stackoverflow.com/a/12014834/1984636

https://stackoverflow.com/a/2042829/1984636


9

แม้ว่าฉันจะชอบคำตอบทั้งหมดของมาร์โกฉันคิดว่ามันยุติธรรมที่จะชี้ให้เห็นว่าคุณยังสามารถใช้เฟรมเวิร์กที่เผยแพร่ / สมัครสมาชิกเพื่อให้ได้ผลลัพธ์เดียวกันเช่นถ้าคุณไปกับบัสเหตุการณ์คุณสามารถทำสิ่งต่อไปนี้

ส่วน:

EventBus.getDefault().post(new DoSomeActionEvent()); 

กิจกรรม:

 @Subscribe
onSomeActionEventRecieved(DoSomeActionEvent doSomeActionEvent){
//Do something

}

5

ใน kotlin คุณสามารถเรียกวิธีการกิจกรรมจากส่วนดังต่อไปนี้:

var mainActivity: MainActivity = activity as MainActivity
        mainActivity.showToast() //Calling show toast method of activity

2

สำหรับการเข้าถึงฟังก์ชั่นที่ประกาศในกิจกรรมของคุณผ่านส่วนของคุณโปรดใช้อินเทอร์เฟซดังที่แสดงในคำตอบโดย marco

สำหรับการเข้าถึงฟังก์ชั่นที่ประกาศใน Fragment ของคุณผ่านกิจกรรมของคุณคุณสามารถใช้สิ่งนี้ได้หากคุณไม่มีแท็กหรือรหัส

private void setupViewPager(ViewPager viewPager) {
    //fragmentOne,fragmentTwo and fragmentThree are all global variables
    fragmentOne= new FragmentOne();
    fragmentTwo= new FragmentTwo();
    fragmentThree = new FragmentThree();

    viewPagerAdapteradapter = new ViewPagerAdapter(getSupportFragmentManager());
    viewPagerAdapteradapter.addFragment(fragmentOne, "Frag1");
    viewPagerAdapteradapter.addFragment(fragmentTwo, "Frag2");
    viewPagerAdapteradapter.addFragment(fragmentThree, "Frag3");

    //viewPager has to be instantiated when you create the activity:
    //ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
    //setupViewPager(viewPager);
    //Where R.id.pager is the id of the viewPager defined in your activity's xml page.

    viewPager.setAdapter(viewPagerAdapteradapter);


    //frag1 and frag2 are also global variables
    frag1 = (FragmentOne)viewPagerAdapteradapter.mFragmentList.get(0);
    frag2 = (FragmentTwo)viewPagerAdapteradapter.mFragmentList.get(1);;


    //You can use the variable fragmentOne or frag1 to access functions declared in FragmentOne


}

นี่คือ ViewpagerAdapterClass

    class ViewPagerAdapter extends FragmentPagerAdapter {
    public final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

คำตอบนี้สำหรับ noobs เช่นฉัน ขอให้มีความสุขในวันนี้


1

นี่คือจากคลาสแฟรกเมนต์ ...

((KidsStoryDashboard)getActivity()).values(title_txt,bannerImgUrl);

รหัสนี้จากคลาสกิจกรรม ...

 public void values(String title_txts, String bannerImgUrl) {
    if (!title_txts.isEmpty()) {

//Do something to set text 
    }
    imageLoader.displayImage(bannerImgUrl, htab_header_image, doption);
}

1

ฉันได้ลองด้วยวิธีการทั้งหมดที่แสดงในชุดข้อความนี้และไม่มีวิธีใดที่เหมาะกับฉันลองวิธีนี้ มันใช้งานได้สำหรับฉัน

((MainActivity) getContext().getApplicationContext()).Method();

0

ฉันกำลังมองหาวิธีที่ดีที่สุดในการทำเช่นนั้นเนื่องจากไม่ใช่ทุกวิธีที่เราต้องการเรียกใช้อยู่ในแฟรกเมนต์ที่มีกิจกรรมหลักเดียวกัน

ในส่วนของคุณ

public void methodExemple(View view){

        // your code here

        Toast.makeText(view.getContext(), "Clicked clicked",Toast.LENGTH_LONG).show();
    }

ในกิจกรรมของคุณ

new ExempleFragment().methodExemple(context); 

0

((YourActivityName)getActivity()).functionName();

ตัวอย่าง: ((SessionActivity)getActivity()).changeFragment();

หมายเหตุ: ชื่อคลาสควรเป็นแบบสาธารณะ


0
((your_activity) getActivity).method_name()

your_activityชื่อกิจกรรมของคุณอยู่ที่ไหนและmethod_name()เป็นชื่อของวิธีการที่คุณต้องการโทร


0

สำหรับ Kotlin ลองดูสิ

class DataForm : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Tasks(this).getData()
    }

    fun getResponse(response: String) {
        // code
    }
}

class Tasks(private val context: Any) {
    fun getData() {

        val getContext = (context as DataForm).activity
        val getFragment = (context as DataForm)

        val responseListener = Response.Listener<String> { response ->
            getFragment.getResponse(response)
        }

        val errorListener = Response.ErrorListener { error ->
            error.printStackTrace();
        }

        val stringRequest = StringRequest(Request.Method.GET, url, responseListener, errorListener)
        Volley.newRequestQueue(getContext).add(stringRequest)
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.