2014-10-05 22 views
15

Tôi mới sử dụng Android và rất quen với việc phát triển web. trong javascript khi bạn muốn thực hiện một nhiệm vụ không đồng bộ bạn vượt qua một chức năng như một cuộc tranh cãi (một callback):Android: chuyển tham chiếu hàm tới AsyncTask

http.get('www.example.com' , function(response){ 
    //some code to handle response 
}); 

Tôi đã tự hỏi nếu chúng ta có thể làm tương tự với android của AsyncTask, vượt qua một tài liệu tham khảo chức năng với phương pháp onPostExecute() và nó sẽ chạy.

bất kỳ đề xuất nào?

+0

Đó không phải cách bạn làm điều đó^_ ^. Bạn tạo ra một chủ đề nền bằng cách sử dụng công việc async và mã của bạn aka httprequest đi vào phương thức doInBackground() và bạn định nghĩa lại kiểu chữ cho nó. Sau khi hoạt động nền kết thúc onPostExecute() được gọi là trong đó bạn viết mã để xử lý các phản ứng như bây giờ bạn nhận được để cập nhật quan điểm và tất cả. Có một phương thức progressupdate được kích hoạt khi đạt được tiến trình xác định. Tôi sẽ nhận được liên kết tài liệu trong một thời gian – Rico

+0

http://developer.android.com/reference/android/os/AsyncTask.html – Rico

Trả lời

41

Có khái niệm gọi lại cũng tồn tại rất nhiều trong Java. Trong Java bạn định nghĩa một callback như thế này:

public interface TaskListener { 
    public void onFinished(String result); 
} 

Người ta sẽ thường xuyên tổ các loại định nghĩa người nghe bên trong AsyncTask như thế này:

public class ExampleTask extends AsyncTask<Void, Void, String> { 

    public interface TaskListener { 
     public void onFinished(String result); 
    } 

    ... 
} 

Và một thực hiện đầy đủ các callback trong AsyncTask sẽ trông như thế này:

public class ExampleTask extends AsyncTask<Void, Void, String> { 

    public interface TaskListener { 
     public void onFinished(String result); 
    } 

    // This is the reference to the associated listener 
    private final TaskListener taskListener; 

    public ExampleTask(TaskListener listener) { 
     // The listener reference is passed in through the constructor 
     this.taskListener = listener; 
    } 

    @Override 
    protected String doInBackground(Void... params) { 
     return doSomething(); 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     super.onPostExecute(result); 

     // In onPostExecute we check if the listener is valid 
     if(this.taskListener != null) { 

      // And if it is we call the callback function on it. 
      this.taskListener.onFinished(result); 
     } 
    } 
} 

onPostExecute() được gọi càng sớm càng nhiệm vụ nền kết thúc. Bạn có thể sử dụng toàn bộ điều như thế này:

ExampleTask task = new ExampleTask(new ExampleTask.TaskListener() { 
    @Override 
    public void onFinished(String result) { 
     // Do Something after the task has finished 
    } 
}); 

task.execute(); 

Hoặc bạn có thể xác định TaskListener hoàn toàn riêng rẽ như thế này:

ExampleTask.TaskListener listener = new ExampleTask.TaskListener() { 
    @Override 
    public void onFinished(String result) { 
     // Do Something after the task has finished 
    } 
}; 

ExampleTask task = new ExampleTask(listener);  
task.execute(); 

Hoặc bạn có thể phân lớp TaskListener như thế này:

public class ExampleTaskListener implements TaskListener { 

    @Override 
    public void onFinished(String result) { 

    } 
} 

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

ExampleTask task = new ExampleTask(new ExampleTaskListener());  
task.execute(); 

Bạn có thể dĩ nhiên chỉ ghi đè lên các phương pháp onPostExecute() của AsyncTask, nhưng điều đó là không nên và trong nhiều trường hợp thực hành thực sự khá xấu. Ví dụ, bạn có thể làm điều này:

ExampleTask task = new ExampleTask() { 
    @Override 
    public void onPostExecute(String result) { 
     super.onPostExecute(result); 

     // Your code goes here 
    } 
}; 

này sẽ chỉ làm việc cũng như việc thực hiện ở trên với một giao diện người nghe riêng biệt, nhưng có một vài vấn đề với điều này:

Trước hết bạn thực sự có thể phá vỡ ExampleTask tất cả cùng nhau. Tất cả đều đi xuống cuộc gọi super.onPostExecute() ở trên. Nếu bạn là nhà phát triển ghi đè onPostExecute() như trên và quên bao gồm cuộc gọi siêu hoặc chỉ cần xóa cuộc gọi đó hoặc vì lý do nào đó, phương thức onPostExecute() gốc trong số ExampleTask sẽ không được gọi nữa. Ví dụ: việc thực hiện toàn bộ người nghe với TaskListener đột nhiên sẽ không hoạt động nữa kể từ khi cuộc gọi đến gọi lại được thực hiện trong onPostExecute(). Bạn cũng có thể phá vỡ TaskListener theo nhiều cách khác bằng cách vô tình hoặc vô tình ảnh hưởng đến trạng thái của ExampleTask để nó không hoạt động nữa.

Nếu bạn nhìn vào những gì thực sự xảy ra khi bạn ghi đè lên một phương pháp như thế này hơn là nó sẽ trở nên rõ ràng hơn những gì đang xảy ra.Bằng cách ghi đè onPostExecute() bạn đang tạo một lớp con mới là ExampleTask. Nó sẽ là điều tương tự chính xác như làm điều này:

public class AnotherExampleTask extends ExampleTask { 

    @Override 
    public void onPostExecute(String result) { 
     super.onPostExecute(result); 

     // Your code goes here 
    } 
} 

Tất cả điều này chỉ là ẩn đằng sau một tính năng ngôn ngữ được gọi là lớp nặc danh. Đột nhiên ghi đè lên một phương pháp như thế này có vẻ không sạch sẽ và nhanh chóng nữa phải không?

Để tóm tắt:

  • Trọng một phương pháp như thế này thực sự tạo ra một lớp con mới. Bạn không chỉ cần thêm một cuộc gọi lại, bạn đang sửa đổi cách thức hoạt động của lớp này và có thể vô tình phá vỡ quá nhiều thứ.
  • Lỗi gỡ lỗi như thế này có thể nhiều hơn chỉ là một nỗi đau trong **. Bởi vì đột nhiên ExampleTask có thể ném Exceptions hoặc đơn giản là không hoạt động nữa vì không có lý do rõ ràng, bởi vì bạn không bao giờ thực sự sửa đổi mã của nó.
  • Mỗi lớp phải cung cấp việc triển khai người nghe ở những nơi phù hợp và dự định. Chắc chắn bạn chỉ có thể thêm chúng sau này bằng cách ghi đè onPostExecute() nhưng điều đó luôn luôn rất nguy hiểm. Ngay cả @flup với danh tiếng 13k của anh ấy đã quên bao gồm cuộc gọi super.onPostExecute() trong câu trả lời của anh ấy, hãy tưởng tượng những gì một số khác không phải là nhà phát triển có kinh nghiệm có thể làm!
  • Một chút trừu tượng không bao giờ làm tổn thương bất kỳ ai. Viết trình nghe cụ thể có thể hơi mã hơn, nhưng đó là giải pháp tốt hơn nhiều. Mã sẽ sạch hơn, dễ đọc hơn và dễ bảo trì hơn nhiều. Sử dụng các phím tắt như ghi đè onPostExecute() về cơ bản là hy sinh chất lượng mã cho một chút tiện lợi. Đó là không bao giờ là một ý tưởng tốt một sẽ chỉ gây ra vấn đề trong thời gian dài.
+0

Câu trả lời này có thể được cải thiện bằng cách sử dụng một giao diện 'chung TaskListener ' và 'onFinished (kết quả T) ' –

+0

@ cricket_007 Tôi sẽ không gọi đó là một cải tiến. Mỗi tác vụ phải có người nghe được xác định nghiêm ngặt. Mọi thứ khác có xu hướng dẫn đến các vấn đề thiết kế và triển khai không tốt, ngay cả khi bỏ qua việc xóa loại. –

+0

Mặc dù vậy, nó linh hoạt hơn là tự giới hạn chỉ với các câu trả lời 'Chuỗi'.Tôi đã trả lời một vài câu hỏi bằng cách sử dụng phương pháp gọi lại trên AsyncTask. [Ví dụ] (http://stackoverflow.com/a/36105515/2308683), bạn nói rằng dẫn đến thiết kế xấu? –

2

Trong Java, các hàm có ít công dân hạng nhất hơn trong JavaScript. AsyncTask cung cấp gọi lại như là một phương thức trong lớp, mà bạn nên ghi đè lên.

Xem Make an HTTP request with android cho lớp con của AsyncTask bằng cách triển khai doInBackground tạo yêu cầu web.

Nếu bạn muốn thực hiện nhiều yêu cầu HTTP với các cuộc gọi lại khác nhau, bạn có thể ghi đè RequestTask và triển khai onPostExecute với các triển khai gọi lại khác nhau. Bạn có thể sử dụng một lớp vô danh để mô phỏng việc đóng cửa một callback JavaScript thường được sử dụng:

new RequestTask(){ 
    @Override 
    public void onPostExecute(String result) { 
     // Implementation has read only access to 
     // final variables in calling scope. 
    } 
}.execute("http://stackoverflow.com"); 

Như Xaver cho thấy, bạn cũng có thể tạo ra một giao diện toàn diện cho người nghe. Điều này dường như chỉ hữu ích cho tôi nếu bạn muốn thực hiện một vài hàm onPostExecute mặc định và chọn một trong các triển khai mặc định này cho một cuộc gọi cụ thể.

+0

Ghi đè 'onPostExecute()' như thế này hiếm khi là một ý tưởng hay. Các lớp học phải cung cấp chức năng người nghe, nơi nó phù hợp và dự định. Những gì bạn đang làm là nguy hiểm theo nhiều cách, chủ yếu là bởi vì nó có thể phá vỡ 'RequestTask' tất cả cùng nhau. Xem phần dưới cùng của câu trả lời của tôi. –

+0

@XaverKapeller Trên thực tế, 'onPostExecute' của lớp siêu không làm điều gì và gọi nó là khá vô nghĩa. Các 'onPostExecute' * là * gọi lại, không phải một số phương pháp thực hiện nội bộ bạn có thể lẻn móc vào. Mục đích của nó là thông báo kết quả cho người sáng tạo ban đầu của nhiệm vụ. – flup

+0

Vâng, đó là sự thật nếu bạn đang thực hiện một 'AsyncTask' mới, nhưng nếu bạn đã phân lớp 'AsyncTask' như' RequestTask' trong câu trả lời của bạn thì bạn có thể phá vỡ bất kỳ chức năng nào đã được triển khai trong 'RequestTask'. Đó là ý tôi trong bình luận trước của tôi. –

Các vấn đề liên quan