Gọi một phương thức hoạt động từ một đoạn


318

Cố gắng gọi một phương thức trong hoạt động của tôi từ một mảnh. Tôi muốn đoạn này cung cấp dữ liệu phương thức và lấy dữ liệu khi phương thức trở lại. Tôi muốn đạt được tương tự như gọi trên một phương thức tĩnh, nhưng không sử dụng tĩnh vì nó tạo ra các vấn đề trong hoạt động.

Mới đối với những mảnh vỡ nên tôi cần một lời giải thích dễ dàng và sư phạm!

Cảm ơn!

Câu trả lời:


820

Từ mảnh đến hoạt động:

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

Từ hoạt động đến phân đoạn:

FragmentManager fm = getSupportFragmentManager();

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

Nếu bạn đã thêm đoạn qua mã và sử dụng tagchuỗi khi bạn thêm đoạn, hãy sử dụng findFragmentByTagthay thế:

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

5
Hãy cẩn thận vì những điều bất ngờ xảy ra nếu diễn viên không hoạt động ..: S
Ewoks

48
Để tránh sự cố diễn viên, hãy sử dụng: Activity act = getActivity (); if (hành động thể hiện YourActivityClassName) ((YourActivityClassName) hành động) .yourPublicMethod (); }
ericharlow

@Richard: Làm thế nào chúng ta có thể thực hiện hành động ngược lại, như, nếu chúng ta phải thực hiện phương thức của một đoạn trong Hoạt động?
Himanshu

5
Đó là thiết kế xấu và không an toàn để tạo một Hoạt động. Một đoạn không giới hạn trong một Hoạt động cụ thể.
Manila Ben Shabat 1/03/2015

3
@Kay Không nhất thiết. Các mảnh vỡ có thể được sử dụng như "các mảnh vỡ" của bất kỳ hoạt động lớn nào bị phá vỡ. Để tạo UI đáp ứng chẳng hạn. Tôi hiếm khi sử dụng cùng một đoạn và gắn nó vào các máy chủ hoạt động khác nhau.
Richard

201

Bạn có lẽ nên cố gắng tách rời đoạn từ hoạt động trong trường hợp bạn muốn sử dụng nó ở một nơi khác. Bạn có thể làm điều này bằng cách tạo một giao diện mà hoạt động của bạn thực hiện.

Vì vậy, bạn sẽ xác định một giao diện như sau:

Giả sử ví dụ bạn muốn cung cấp cho hoạt động một Chuỗi và để nó trả về một Số nguyên:

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

Điều này có thể được xác định trong đoạn hoặc một tệp riêng biệt.

Sau đó, bạn sẽ có hoạt động của bạn thực hiện giao diện.

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

}

Sau đó, trong đoạn của bạn, bạn sẽ có một biến MyStringListener và bạn sẽ đặt trình nghe theo phương thức phân đoạn onAttach (Hoạt động hoạt động).

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. */
            }
        }

    }

chỉnh sửa (17.12.2015):onAttach(Activity activity) is deprecated, use onAttach(Context context) instead, it works as intended

Câu trả lời đầu tiên chắc chắn có tác dụng nhưng nó kết hợp đoạn hiện tại của bạn với hoạt động của máy chủ. Thực hành tốt của nó để giữ cho các mảnh được tách ra khỏi hoạt động của máy chủ trong trường hợp bạn muốn sử dụng nó trong một tính nhạy cảm khác.


58
Đối với bất cứ ai khác nhìn vào điều này, trong khi câu trả lời được chấp nhận rõ ràng có tác dụng, đây là cách tiếp cận tốt hơn và an toàn hơn từ góc độ thiết kế.
Paul Richter

7
Câu trả lời này tốt hơn nhiều về mặt thiết kế mã. ngoài ra, nó sẽ không gây ra sự cố nếu hoạt động bị bỏ qua
David T.

3
+1 nhưng tôi sẽ không sử dụng tính năng thử trong onAttach. Hãy để nó thất bại. Nếu trình nghe là tùy chọn (nghĩa là thất bại là không phù hợp), hãy thêm phương thức set / addListener vào đoạn.
ataulm

Đối với giao tiếp phía đối diện, vui lòng xem: developer.android.com/training/basics/fragments/ ,. Sử dụng giao diện của đoạn (cũng là cách an toàn để thực hiện phân đoạn-> hoạt động comm như đã giải thích ở trên), bạn có thể gọi một phương thức trong phân đoạn của mình từ hoạt động của mình nếu bạn muốn thực hiện một hành động dựa trên phân đoạn của mình-> hoạt động thông tin
Kerem

Các mảnh được sử dụng lại và được đặt trong bất kỳ Hoạt động nào. Nếu tôi có 5 hoạt động sử dụng cùng một mảnh thì sao? Câu trả lời của Marco là câu trả lời đúng và là một cách thực hành tốt cho giao tiếp giữa các phân đoạn và Hoạt động phân mảnh
blockwala

51

Dành cho nhà phát triển Kotlin

(activity as YourActivityClassName).methodName()

Dành cho nhà phát triển Java

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

nó báo lỗi trong kotlin nếu chúng ta chạy mã này .. có cách nào khác không?
Jake Garbo

1
Khi tôi chạy nó. Tôi nhận được giá trị null của ActivityClass, tôi nghĩ rằng đây không phải là cách thích hợp để làm điều này trong kotlin thậm chí không có lỗi. hoặc có thể là một lỗi?
Jake Garbo

@JakeGarbo Cách đúng đắn của nó nếu không 12 người đã không bỏ phiếu cho nó. điều thứ hai đôi khi getActivity () trả về null kiểm tra những câu hỏi đó trên SO.
Wasim K. Memon

@JakeGarbo Ya họ nói với bạn. NẾU nó làm việc cho bạn sau đó đánh giá cao nó hoặc tìm cách khác hoặc tìm hiểu cách viết mã trước.
Wasim K. Memon

13

Cập nhật sau khi tôi hiểu thêm làm thế nào các mảnh vỡ hoạt động. Mỗi mảnh thuộc về một hoạt động cha mẹ. Vì vậy, chỉ cần sử dụng:

getActivity().whatever

Từ trong mảnh vỡ. Đó là một câu trả lời tốt hơn bởi vì bạn tránh các diễn viên thừa. Nếu bạn không thể tránh các phôi với giải pháp này, hãy sử dụng cách dưới đây.

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

những gì bạn phải làm là chuyển sang hoạt động bên ngoài

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

tạo một thể hiện mới sẽ gây nhầm lẫn cho khung Android và nó sẽ không thể nhận ra nó. Xem thêm :

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

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


9

Mặc dù tôi hoàn toàn thích Câu trả lời của Marco nhưng tôi nghĩ thật công bằng khi chỉ ra rằng bạn cũng có thể sử dụng khung dựa trên xuất bản / đăng ký để đạt được kết quả tương tự, ví dụ nếu bạn đi bằng xe buýt sự kiện, bạn có thể làm như sau

miếng :

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

Hoạt động:

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

}

5

Trong kotlin, bạn có thể gọi phương thức hoạt động từ đoạn như dưới đây:

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

2

Để truy cập một chức năng được khai báo trong Hoạt động của bạn thông qua đoạn của bạn, vui lòng sử dụng một giao diện, như được hiển thị trong câu trả lời của marco.

Để truy cập một hàm được khai báo trong Fragment thông qua hoạt động của bạn, bạn có thể sử dụng hàm này nếu bạn không có thẻ hoặc id

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


}

Đây là ViewpagerAd CHƯƠNGClass

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

Câu trả lời này là dành cho những người mới như tôi. Chúc bạn ngày mới tốt lành.


1

Đây là từ lớp Fragment ...

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

Mã này từ lớp hoạt động ...

 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

Tôi đã thử với tất cả các phương thức được hiển thị trong chuỗi này và không có phương pháp nào phù hợp với tôi, hãy thử phương pháp này. Nó làm việc cho tôi.

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

0

Tôi đã tìm kiếm cách tốt nhất để làm điều đó vì không phải mọi phương thức chúng tôi muốn gọi đều nằm trong Fragment với cùng Activity Parent.

Trong mảnh vỡ của bạn

public void methodExemple(View view){

        // your code here

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

Trong hoạt động của bạn

new ExempleFragment().methodExemple(context); 

0

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

Thí dụ : ((SessionActivity)getActivity()).changeFragment();

Lưu ý: tên lớp phải ở nơi công cộng


0
((your_activity) getActivity).method_name()

Trong trường hợp your_activitylà tên của hoạt động của bạn và method_name()là tên của phương pháp mà bạn muốn gọi.


0

Đối với Kotlin hãy thử nó

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)
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.