2012-04-20 10 views
7

Đây là mã của tôi:cuối cùng biến địa phương có thể không có được khởi tạo trong lớp bên trong vô danh

final Foo myFoo = new Foo(new Inner() { 
    @Override 
    callback(){ 
     myFoo.bar(); 
    } 
}); 

(Với tên hàm thực tế)

final MyArrayAdapter aa = new MyArrayAdapter(new View.OnClickListener() { 
    @Override 
    onClick(){ 
     aa.notifyDataSetChanged(); 
    } 
}); 

Java là cho tôi một lỗi về cách myFoo sức mạnh chưa được khởi tạo. Có cách nào để sửa lỗi này không? Tôi có khả năng có thể thiết lập gọi lại để null khi tôi xây dựng các đối tượng và sau đó thay đổi nó sau đó, nhưng tôi hy vọng cho có được một cách sạch hơn. Bất kỳ ý tưởng? (Cũng sẽ không hiệu quả nếu Foo không được viết bởi tôi và không tiết lộ giao diện để thay đổi cuộc gọi lại sau)

Trong trường hợp bất kỳ ai tò mò, trong trường hợp cụ thể của tôi, Foo là một ArrayAdapter và bar là notifyDataSetChanged(). Những gì được hiển thị bởi bộ điều hợp phụ thuộc vào giá trị của các mục trong mảng và các giá trị đó thay đổi khi chúng được nhấp vào. Gọi lại là clickListener.

+1

Bạn có thể không chỉ tham khảo _this.bar() _ hoặc _bar() _? –

+0

không, mã thực tế của tôi phức tạp hơn ví dụ này và hàm gọi lại nằm trong một lớp bên trong ẩn danh khác – Drew

+0

Tại sao bạn ghi đè notificationDataSetChanged? Từ tài liệu API, có vẻ như bạn nên gọi myFoo.registerDataSetObserver (new DataSetObserver() {}). – sharakan

Trả lời

6

Câu trả lời ngắn gọn là bạn chắc chắn không thể làm điều đó trong Java, nhưng trình biên dịch đã nói với bạn điều đó. Bạn đang cố gắng để tạo ra hai đối tượng cùng một lúc với tài liệu tham khảo với nhau, đó là một vấn đề gà và trứng. Tóm lại, bạn phải tạo MỘT trong số họ trước tiên.

Một gợi ý là một sáng tạo hai bước:

.... 
final MyArrayAdapter aa = new MyArrayAdapter(); 
aa.initializeButtonClickListener(); 
.... 

và sau đó thêm các phương pháp 'khởi tạo' để adapter.

public void initializeButtonClickListener(){ 
    this.button.setOnClickListener(new View.OnClickListener() { 
     @Override 
     onClick(){ 
      notifyDataSetChanged(); 
     } 
    }); 
} 

Bởi vì xây dựng được một chút phức tạp (ví dụ phức tạp hơn chỉ đơn giản là gọi một constructor), tôi khuyên bạn nên sau đó kéo hai dòng trong một phương pháp MyArrayAdapter nhà máy, và làm cho tư nhân xây dựng.

+0

OK, tôi có thể thấy tại sao điều này là không thể. Tôi viết lại nó để thiết lập cuộc gọi lại sau khi đối tượng đầu tiên được tạo. Tôi không chắc chắn lý do tại sao tôi không nên gọi notifyDataSetChanged() mặc dù, tôi muốn vẽ lại tất cả mọi thứ khi một phần tử của mảng thay đổi. – Drew

+0

Hmm ... Tôi nghĩ tôi đã nhầm lẫn với những cái tên trong ví dụ của bạn. Tôi nghĩ rằng Inner là một DataSetObserver, được gọi bởi Adapter, không gọi nó. Đối tượng mà ClickListener (tức là Inner) đang lắng nghe ở đâu? Tôi sẽ nghĩ rằng sẽ có ba dòng: tạo một ArrayAdapter, tạo một ClickListener gọi .notifyDataSetChanged, sau đó tạo một đối tượng 'có thể nhấp' (xem, tôi giả sử) sử dụng ArrayAdapter vì nó là 'mô hình', và sau đó gọi view.setOnClickListener (người nghe) để hoàn thành vòng tròn. – sharakan

+0

Được rồi, tôi đã thêm một phiên bản với kịch bản thực tế của mình. Nút mà trình nghe click được gắn vào bên trong bộ điều hợp. – Drew

0

Bạn có thể khai báo một phương pháp callBarOnMyFoo trong lớp chứa và gọi nó là từ gọi lại của bạn:

void callBarOnMyFoo() { 
    myFoo.bar(); 
} 

Sau đó gọi lại của bạn sẽ cần phải gọi callBarOnMyFoo, mà là một phương pháp thể hiện của các lớp bên ngoài, mà Inner mã nên có một tham chiếu đến (tôi quên cú pháp cho nó offhand).

+0

myFoo là một biến địa phương mặc dù, và callBarOnMyFoo sẽ không có quyền truy cập vào nó.Tôi đoán tôi có thể biến nó thành một thành viên, nhưng điều đó có vẻ xấu xí như giải pháp thiết lập người nghe của tôi sau khi xây dựng – Drew

3

này sẽ làm việc nói chung và không được tiếp cận định nghĩa Inner, nhưng bạn cần phải tạo ra một lớp helper:

class CallbackHelper { 
    private Foo foo; 
    public void setFoo(Foo f){ foo = f; } 
    public Foo getFoo(){ return foo; } 
} 

Và sau đó sử dụng nó như thế này:

final CallbackHelper cbh = new CallbackHelper(); 
Foo myFoo = new Foo(new Inner() { 
    @Override 
    callback(){ 
     cbh.getFoo().bar(); 
    } 
}); 
cbh.setFoo(myFoo);