Phương thức Hoạt động cuộc gọi từ bộ điều hợp


119

Có thể gọi phương thức được định nghĩa trong Activitytừ ListAdapterkhông?

(Tôi muốn thực hiện một Buttontrong list'shàng và khi nút này được nhấn vào, nó sẽ thực hiện các phương pháp, đó là quy định tại Hoạt động tương ứng. Tôi cố gắng để thiết lập onClickListenertrong tôi ListAdapternhưng tôi không biết làm thế nào để gọi phương pháp này, đường đi của nó là gì. ..)

khi tôi sử dụng, Activity.this.method()tôi gặp lỗi sau:

No enclosing instance of the type Activity is accessible in scope

Bất kỳ ý tưởng ?


bạn không thể gọi activity.this trong một số lớp khác trừ khi nó là một lớp bên trong của hoạt động đó. làm theo @Eldhose M Babu giải pháp cho trường hợp của bạn
Archie.bpgc

Câu trả lời:


306

Có bạn có thể.

Trong bộ điều hợp Thêm một Trường mới:

private Context mContext;

Trong bộ điều hợp Constructor, hãy thêm mã sau:

public AdapterName(......, Context context) {
  //your code.
  this.mContext = context;
}

Trong getView (...) của Bộ điều hợp:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
  @Override
  public void onClick(View v) {
    if (mContext instanceof YourActivityName) {
      ((YourActivityName)mContext).yourDesiredMethod();
    }
  }
});

thay thế bằng tên lớp của riêng bạn nơi bạn thấy mã của mình, hoạt động của bạn, v.v.

Nếu bạn cần sử dụng cùng một bộ điều hợp này cho nhiều hoạt động thì:

Tạo giao diện

public interface IMethodCaller {
    void yourDesiredMethod();
}

Triển khai giao diện này trong các hoạt động bạn yêu cầu để có chức năng gọi phương thức này.

Sau đó, trong Bộ điều hợp getView (), gọi như sau:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mContext instanceof IMethodCaller) {
            ((IMethodCaller) mContext).yourDesiredMethod();
        }
    }
});

Bạn xong việc rồi. Nếu bạn cần sử dụng bộ điều hợp này cho các hoạt động không yêu cầu cơ chế gọi này, mã sẽ không thực thi (Nếu kiểm tra không thành công).


29
Vì đây là một câu hỏi phổ biến, tôi thực sự đề nghị KHÔNG SỬ DỤNG giải pháp này. Bạn nên tránh truyền lớp ở đây, vì điều này có thể dẫn đến ngoại lệ thời gian chạy.
Igor Filippov

3
Eldhose anh bạn, tôi không có gì chống lại bạn nhưng câu trả lời dưới đây là phương pháp hay nhất. Bạn thậm chí có thể đọc trong các bình luận. Bạn không nên truyền mContext tới Activity của mình vì bạn đang tránh sử dụng lại mã. Bây giờ bộ điều hợp này chỉ có thể được sử dụng bên trong Hoạt động mà bạn đã truyền biến mContext của mình tới, nơi nếu bạn đã xác định trình nghe thì bạn có thể sử dụng lại Bộ điều hợp tương tự trong một Hoạt động khác. Hãy tin tưởng tôi, tôi đã dành đủ thời gian cho ngành công nghiệp và tôi chỉ đang cố gắng giúp bạn ở đây, vui lòng không coi đó là cá nhân.
Varundroid

2
Giải pháp này là một trong những giải pháp tốt nhất mà tôi từng tìm thấy trên SO. Vì vậy, cảm ơn rất nhiều ông Babu. Gọi các phương thức của Activity bằng cách này, giúp toàn bộ ứng dụng tăng hiệu suất 500% -> Tôi không cần tải lại cơ sở dữ liệu trong bộ điều hợp, mà tôi cần truy cập. Tôi không quan tâm đến "số năm trong ngành", tôi đang tìm kiếm các giải pháp ổn định và hoạt động và tôi khá chắc chắn, tôi sẽ không tìm ra cách tốt hơn để tiếp cận. Có lẽ tôi có thể thiết lập DB như một singleton, nhưng đây không phải là cách tôi muốn "hủy cấu trúc" dự án của mình.
Martin Pfeffer

2
@RAM nếu bạn cần gọi cùng một phương thức trong nhiều hoạt động, bạn cần tạo một giao diện với tên phương thức đó. Sau đó, triển khai giao diện đó trong tất cả các hoạt động mà bạn cần phương thức gọi được đưa vào lịch sử. Sau đó, trong trình nghe nhấp chuột, hãy kiểm tra phiên bản giao diện của bạn thay vì sử dụng tên hoạt động.
Eldhose M Babu

1
Câu trả lời tuyệt vời. Thumbs up
Alok Rajasukumaran

126

Bạn có thể làm theo cách này:

Khai báo giao diện:

public interface MyInterface{
    public void foo();
}

Hãy để Hoạt động của bạn bổ sung nó:

public class MyActivity extends Activity implements MyInterface{
    public void foo(){
        //do stuff
    }
}

Sau đó, chuyển hoạt động của bạn đến ListAdater:

public MyAdapter extends BaseAdater{
    private MyInterface listener;

    public MyAdapter(MyInterface listener){
        this.listener = listener;
    }
}

Và ở đâu đó trong bộ điều hợp, khi bạn cần gọi phương thức Hoạt động đó:

listener.foo();

5
Lần đầu tiên tôi nghĩ về phương pháp ở trên giống như bạn làm với các mảnh vỡ nhưng đây là giải pháp tốt nhất!
brux

1
nào là InterfaceListener của tôi? làm thế nào có thể khởi tạo nó? public MyAdapter (MyInterface listening) {this.listener = listening; }
Gilberto Ibarra

6
Làm cách nào để bạn chuyển giao diện sang bộ điều hợp (từ Hoạt động)
Brandon

1
@Brandon bạn có thể chuyển nó là tham số khởi tạo trong bộ điều hợp.
Igor Filippov

5
@Brandon, chỉ cần thêm 'this' để chuyển giao diện sang bộ điều hợp myAdapter = new MyAdapter (this);
ajinkya

67

Nguyên:

Tôi hiểu câu trả lời hiện tại nhưng cần một ví dụ rõ ràng hơn. Đây là một ví dụ về những gì tôi đã sử dụng với Adapter(RecyclerView.Adapter) và mộtActivity .

Trong Hoạt động của bạn:

Điều này sẽ thực hiện những interfacegì chúng tôi có trong của chúng tôi Adapter. Trong ví dụ này, nó sẽ được gọi khi người dùng nhấp vào một mục trong RecyclerView.

public class MyActivity extends Activity implements AdapterCallback {

    private MyAdapter myAdapter;

    @Override
    public void onMethodCallback() {
       // do something
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        myAdapter = new MyAdapter(this);
    }
}

Trong Bộ điều hợp của bạn:

Trong Activity, chúng tôi đã khởi tạo của chúng tôi Adaptervà chuyển điều này làm đối số cho trình tạo. Điều này sẽ bắt đầu interfacecho phương thức gọi lại của chúng tôi. Bạn có thể thấy rằng chúng tôi sử dụng phương pháp gọi lại cho các lần nhấp của người dùng.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private AdapterCallback adapterCallback;

    public MyAdapter(Context context) {
        try {
            adapterCallback = ((AdapterCallback) context);
        } catch (ClassCastException e) {
            throw new ClassCastException("Activity must implement AdapterCallback.", e);
        }
    }

    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int position) {
        // simple example, call interface here
        // not complete
        viewHolder.itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    adapterCallback.onMethodCallback();
                } catch (ClassCastException e) {
                   // do something
                }
            }
        });
    }

    public static interface AdapterCallback {
        void onMethodCallback();
    }
}

6
cảm ơn vì điều này, đó chính xác là những gì tôi đang tìm kiếm. được bình chọn
Nactus

điều này đã làm việc cho tôi! imo, mã làm việc hoàn chỉnh nhất cho đến nay!
publicknowledge, 09/07/2016

2
Cảm ơn vì giải pháp này
Steve.

4
câu trả lời này sẽ có nhiều ủng hộ hơn, đây là một giải pháp sạch sẽ và hoàn hảo.
Opiatefuchs

Xin chào @Jared - Bạn có thể chọn đúng mẫu EventBusnhư bạn đề xuất không?
Tohid 27/02/17

15

Cơ bản và đơn giản.

Trong bộ điều hợp của bạn chỉ cần sử dụng cái này.

((YourParentClass) context).functionToRun();


4
không phải là một phương pháp hay vì bạn đang hạn chế lớp của mình chỉ hoạt động với kiểu YourParentClass thay vì bất kỳ lớp nào, nhưng hoạt động nếu bạn không quan tâm đến việc sử dụng lại nó, nếu bạn cũng đổi tên một lớp thì mã sẽ bị hỏng ...
Gustavo Baiocchi Costa

7

Một cách nữa là ::

Viết một phương thức trong bộ điều hợp của bạn cho phép nói public void callBack () {}.

Bây giờ trong khi tạo một đối tượng cho bộ điều hợp trong hoạt động ghi đè phương thức này. Phương thức ghi đè sẽ được gọi khi bạn gọi phương thức trong bộ điều hợp.

Myadapter adapter = new Myadapter() {
  @Override
  public void callBack() {
    // dosomething
  }
};

5

Đối với Kotlin:

Trong bộ điều hợp của bạn, chỉ cần gọi

(context as Your_Activity_Name).yourMethod()

0
if (parent.getContext() instanceof yourActivity) {
  //execute code
}

điều kiện này sẽ cho phép bạn thực thi một cái gì đó nếu Activity có GroupViewyêu cầu lượt xem từ getView()phương thức của bạn adapteryourActivity

LƯU Ý: parentđó là GroupView


GroupView này yêu cầu quan điểm từ các bộ chuyển đổi khi nó gọi là getView()phương pháp ..... vì vậy chúng tôi có được bối cảnh đó GroupView, và kiểm tra nó thông qua các điều kiện nêu trên
Abd Salam Baker

0

Trong Kotlin bây giờ có một cách gọn gàng hơn bằng cách sử dụng các hàm lambda, không cần giao diện:

class MyAdapter(val adapterOnClick: (Any) -> Unit) {
    fun setItem(item: Any) {
        myButton.setOnClickListener { adapterOnClick(item) }
    }
}

class MyActivity {
    override fun onCreate(savedInstanceState: Bundle?) {
        var myAdapter = MyAdapter { item -> doOnClick(item) }
    }


    fun doOnClick(item: Any) {

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