Bên trong OnClickListener, tôi không thể truy cập nhiều thứ - làm thế nào để tiếp cận?


79

Bên trong OnClickListener, tôi không thể truy cập hầu hết các biến "bên ngoài" phạm vi, như sau:

findViewById(R.id.Button01).setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent mainApps = new Intent(Intent.ACTION_MAIN);
                mainApps.addCategory(Intent.CATEGORY_LAUNCHER);
                List<ActivityInfo> activities = this.getPackageManager().queryIntentActivities(mainApps, 0);
                /*
                Intent intent = new Intent("com.sygic.drive/com.sygic/drive/.SygicDriveActivity");
                startActivity(intent);*/
            }

        });

trong ví dụ này, tôi cần tải PacketManager và tôi không thể lấy nó vì tôi không có sẵn Ngữ cảnh bên trong OnClickListener.

Tôi có thể tạo một tham chiếu tĩnh bên ngoài và sử dụng nó bên trong, nhưng điều đó có chính xác không? Có vẻ kỳ lạ khi phải làm điều đó mọi lúc?

Câu trả lời:


231

Thay thế thismã của bạn trong MyActivity.thisđó MyActivity là tên lớp của lớp con Hoạt động của bạn.

Giải thích: Bạn đang tạo một lớp bên trong ẩn danh khi sử dụng phần mã này của mình:
new OnClickListener() {
Các lớp bên trong ẩn danh có tham chiếu đến phiên bản của lớp mà chúng được tạo. Có vẻ như bạn đang tạo nó bên trong một lớp con Hoạt động vì findViewById là một Phương pháp hoạt động. Hoạt động là một Ngữ cảnh, vì vậy tất cả những gì bạn cần làm là sử dụng tham chiếu đến nó mà bạn có tự động.


1
Tôi đã truy cập Google trong một thời gian chỉ để tìm "MyActivity.this". Nó có vẻ rất đơn giản bây giờ. Cảm ơn bạn về thông tin!
TCCV

Điều gì về việc truy cập các biến gây ra lỗi Cannot refer to a non-final variable table inside an inner class defined in a different method? Tôi không thể truy cập chúng qua MyActivity.this.
Michael

Đó là các biến cục bộ. Nếu họ không thay đổi, bạn có thể thay đổi tuyên bố của họ để có giá trị cuối cùng. Nếu chúng thay đổi, nhưng trước khi lớp bên trong của bạn được xác định, bạn chỉ có thể xác định phiên bản cuối cùng ngay trước đó. Vd: final int myFinalErrorCode = errorCode. Nếu không, bạn phải làm điều gì đó như tạo và thiết lập một thành viên trên hoạt động mà bạn truy cập hoặc trong lớp bên trong.
Lance Nanek

Tôi không hiểu hành vi này, nhưng Nó hoạt động như bạn đã nói Activity.this.doStg(). Bạn có thể xem tại đây @LanceNanek một số url với lời giải thích chi tiết hơn xin vui lòng. Nó có liên quan bằng cách nào đó với lập trình phản ứng không?
murt

Xem ví dụ "ShadowTest.this" tại đây: docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Lance Nanek

10

Bạn cũng có thể triển khai giao diện OnClickListener trong lớp của mình và tránh sự cần thiết của một lớp bên trong ẩn danh. Sau đó, bạn sẽ đặt trình nghe khi nhấp chuột như thế này:

findViewById(R.id.Button01).setOnClickListener(this);

Nếu bạn có nhiều nút bằng cách sử dụng một trình nghe, bạn có thể sử dụng câu lệnh switch với view.getId () (tương ứng với id của chế độ xem trong R.id) để phân biệt giữa chúng.


4

Có một số điều bạn có thể làm, bạn có thể tạo một lớp bên trong triển khai onClickListener và chuyển các đối số cần thiết vào phương thức khởi tạo của lớp. Tôi vẫn không thấy đó là cách tiếp cận sạch sẽ nhất. Tôi thường chỉ tạo một phương thức khác để thực hiện hành động của mình. Vì vậy, trong onClick (View v), tôi sẽ làm một cái gì đó như thế này.

onClick(View v){doMyAction(myParams)}

private void doMyAction(Object params){//do stuff}

Và chỉ cần chuyển các tham số cần thiết từ phương thức của người nghe sang phương thức bên ngoài trình nghe.


Được rồi, bạn phải làm theo cách đó, nhưng tôi đoán nó hoạt động. =)
Ted

0

Thay đổi phương thức khởi tạo Intent đang sử dụng thành Intent (ngữ cảnh, tên lớp) và sử dụng getApplicationContext () trong lớp bên trong của bạn. Giải quyết vấn đề của tôi anyway.

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.