2013-05-28 39 views
46

Tôi quen thuộc với khung công tác Android và Java và muốn tạo một lớp "NetworkHelper" chung để xử lý hầu hết mã mạng cho phép tôi chỉ gọi các trang web từ đó.Chuyển chức năng như một tham số trong java

Tôi đi theo bài viết này từ developer.android.com để tạo ra lớp mạng của tôi: http://developer.android.com/training/basics/network-ops/connecting.html

Code:

package com.example.androidapp; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.Reader; 
import java.io.UnsupportedEncodingException; 
import java.net.HttpURLConnection; 
import java.net.URL; 

import android.content.Context; 
import android.net.ConnectivityManager; 
import android.net.NetworkInfo; 
import android.os.AsyncTask; 
import android.util.Log; 



/** 
* @author tuomas 
* This class provides basic helper functions and features for network communication. 
*/ 


public class NetworkHelper 
{ 
private Context mContext; 


public NetworkHelper(Context mContext) 
{ 
    //get context 
    this.mContext = mContext; 
} 


/** 
* Checks if the network connection is available. 
*/ 
public boolean checkConnection() 
{ 
    //checks if the network connection exists and works as should be 
    ConnectivityManager connMgr = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); 

    if (networkInfo != null && networkInfo.isConnected()) 
    { 
     //network connection works 
     Log.v("log", "Network connection works"); 
     return true; 
    } 
    else 
    { 
     //network connection won't work 
     Log.v("log", "Network connection won't work"); 
     return false; 
    } 

} 

public void downloadUrl(String stringUrl) 
{ 
    new DownloadWebpageTask().execute(stringUrl); 

} 



//actual code to handle download 
private class DownloadWebpageTask extends AsyncTask<String, Void, String> 
{ 



    @Override 
    protected String doInBackground(String... urls) 
    { 
     // params comes from the execute() call: params[0] is the url. 
     try { 
      return downloadUrl(urls[0]); 
     } catch (IOException e) { 
      return "Unable to retrieve web page. URL may be invalid."; 
     } 
    } 

    // Given a URL, establishes an HttpUrlConnection and retrieves 
    // the web page content as a InputStream, which it returns as 
    // a string. 
    private String downloadUrl(String myurl) throws IOException 
    { 
     InputStream is = null; 
     // Only display the first 500 characters of the retrieved 
     // web page content. 
     int len = 500; 

     try { 
      URL url = new URL(myurl); 
      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
      conn.setReadTimeout(10000); 
      conn.setConnectTimeout(15000); 
      conn.setRequestMethod("GET"); 
      conn.setDoInput(true); 
      // Starts the query 
      conn.connect(); 
      int response = conn.getResponseCode(); 
      Log.d("log", "The response is: " + response); 
      is = conn.getInputStream(); 

      // Convert the InputStream into a string 
      String contentAsString = readIt(is, len); 
      return contentAsString; 

     // Makes sure that the InputStream is closed after the app is 
     // finished using it. 
     } finally { 
      if (is != null) { 
       is.close(); 
      } 
     } 
    } 

    // Reads an InputStream and converts it to a String. 
    public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException 
    { 
     Reader reader = null; 
     reader = new InputStreamReader(stream, "UTF-8");   
     char[] buffer = new char[len]; 
     reader.read(buffer); 
     return new String(buffer); 
    } 


    // onPostExecute displays the results of the AsyncTask. 
    @Override 
    protected void onPostExecute(String result) 
    { 
     //textView.setText(result); 
     Log.v("log", result); 

    } 

} 

}

Trong lớp hoạt động của tôi, tôi sử dụng lớp cách này :

connHelper = new NetworkHelper(this); 

...

if (connHelper.checkConnection()) 
    { 
     //connection ok, download the webpage from provided url 
     connHelper.downloadUrl(stringUrl); 
    } 

Vấn đề tôi đang gặp phải là bằng cách nào đó tôi phải thực hiện gọi lại cho hoạt động và cần được xác định trong hàm "downloadUrl()". Ví dụ khi tải xuống kết thúc, công khai void "handleWebpage (String dữ liệu)" chức năng trong hoạt động được gọi là với chuỗi nạp như tham số của nó.

Tôi đã làm một số googling và thấy rằng tôi bằng cách nào đó nên sử dụng giao diện để đạt được chức năng này. Sau khi xem xét một số câu hỏi/câu trả lời tương tự như trên stackoverflow, tôi không hiểu nó hoạt động như thế nào và tôi không chắc liệu mình có hiểu được giao diện đúng hay không: How do I pass method as a parameter in Java? Thành thật mà nói, sử dụng các lớp ẩn danh là mới đối với tôi. nên áp dụng các đoạn mã ví dụ trong chuỗi đã đề cập.

Vì vậy, câu hỏi của tôi là làm thế nào tôi có thể vượt qua chức năng gọi lại đến lớp mạng của tôi và gọi nó sau khi tải xuống kết thúc? Trường hợp khai báo giao diện, thực hiện từ khóa, v.v ...? Xin lưu ý rằng tôi mới bắt đầu với Java (có nền tảng lập trình khác mặc dù) vì vậy tôi đánh giá cao một lời giải thích trong suốt :) Cảm ơn bạn!

Trả lời

75

Sử dụng giao diện gọi lại hoặc lớp trừu tượng với phương thức gọi lại trừu tượng. giao diện

Callback dụ:

public class SampleActivity extends Activity { 

    //define callback interface 
    interface MyCallbackInterface { 

     void onDownloadFinished(String result); 
    } 

    //your method slightly modified to take callback into account 
    public void downloadUrl(String stringUrl, MyCallbackInterface callback) { 
     new DownloadWebpageTask(callback).execute(stringUrl); 
    } 

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

     //example to modified downloadUrl method 
     downloadUrl("http://google.com", new MyCallbackInterface() { 

      @Override 
      public void onDownloadFinished(String result) { 
       // Do something when download finished 
      } 
     }); 
    } 

    //your async task class 
    private class DownloadWebpageTask extends AsyncTask<String, Void, String> { 

     final MyCallbackInterface callback; 

     DownloadWebpageTask(MyCallbackInterface callback) { 
      this.callback = callback; 
     } 

     @Override 
     protected void onPostExecute(String result) { 
      callback.onDownloadFinished(result); 
     } 

     //except for this leave your code for this class untouched... 
    } 
} 

Lựa chọn thứ hai thậm chí còn ngắn gọn hơn. Bạn thậm chí không phải định nghĩa một phương thức trừu tượng cho "sự kiện onDownloaded" là onPostExecute thực hiện chính xác những gì cần thiết. Chỉ cần mở rộng DownloadWebpageTask của bạn với lớp nội tuyến ẩn danh bên trong phương thức downloadUrl của bạn.

//your method slightly modified to take callback into account 
    public void downloadUrl(String stringUrl, final MyCallbackInterface callback) { 
     new DownloadWebpageTask() { 

      @Override 
      protected void onPostExecute(String result) { 
       super.onPostExecute(result); 
       callback.onDownloadFinished(result); 
      } 
     }.execute(stringUrl); 
    } 

    //... 
+1

Cảm ơn, điều này đã giúp tôi giải quyết vấn đề và tôi nghĩ bây giờ tôi đã hiểu các khái niệm cơ bản về giao diện :) – Tumetsu

+1

Thú vị khi xem giao diện đóng một vai trò quan trọng trong lập trình java chung như thế nào. –

+3

Điều này xảy ra trước khi java 8 ... –

20

Vâng, giao diện là cách tốt nhất IMHO. Ví dụ, GWT sử dụng mô hình lệnh với một giao diện như thế này:

public interface Command{ 
    void execute(); 
} 

Bằng cách này, bạn có thể vượt qua chức năng từ một phương pháp khác

public void foo(Command cmd){ 
    ... 
    cmd.execute(); 
} 

public void bar(){ 
    foo(new Command(){ 
    void execute(){ 
     //do something 
    } 
    }); 
} 
+6

Whats GWT và cách chuyển bất kỳ tham số nào? – Buksy

+0

@ Buksy là nó những gì bạn đang tìm kiếm? giao diện công khai Lệnh { thực thi void (đối tượng ... đối tượng); } Để vượt qua các đối tượng không giới hạn: D –

9

Các ra khỏi dung dịch hộp là điều này là không thể trong Java. Java không chấp nhận Higher-order functions. Nó có thể đạt được mặc dù bởi một số "thủ đoạn". Thông thường giao diện là giao diện được sử dụng như bạn đã thấy. Vui lòng xem here để biết thêm thông tin. Bạn cũng có thể sử dụng sự phản chiếu để đạt được nó, nhưng đây là lỗi dễ bị.

+1

Điều này không thực sự xứng đáng như một câu trả lời, vì tất cả các bạn làm điều đó cho thấy những gì để xem xét nó sẽ phù hợp hơn như một bình luận. –

+8

Vì anh ta có dưới 50 đại diện anh ta không thể bình luận, chỉ có thể trả lời. Tôi luôn không thích điều đó. –

+1

Câu trả lời khái niệm rất hữu ích, cho các lập trình viên có kinh nghiệm chuyển sang Java. Cảm ơn, @olorin! – Fattie

4

Sử dụng Giao diện có thể là cách tốt nhất trong Kiến trúc mã hóa Java.

Nhưng, việc truyền một đối tượng Runnable cũng có thể hoạt động tốt và nó sẽ thực tế và linh hoạt hơn nhiều.

SomeProcess sp; 

public void initSomeProcess(Runnable callbackProcessOnFailed) { 
    final Runnable runOnFailed = callbackProcessOnFailed; 
    sp = new SomeProcess(); 
    sp.settingSomeVars = someVars; 
    sp.setProcessListener = new SomeProcessListener() { 
      public void OnDone() { 
      Log.d(TAG,"done"); 
      } 
      public void OnFailed(){ 
      Log.d(TAG,"failed"); 
      //call callback if it is set 
      if (runOnFailed!=null) { 
       Handler h = new Handler(); 
       h.post(runOnFailed); 
      } 
      }    
    }; 
} 

/****/ 

initSomeProcess(new Runnable() { 
    @Override 
    public void run() { 
     /* callback routines here */ 
    } 
}); 
+1

Triển khai rất gọn gàng và gọn gàng. – SolidSnake

0

Reflection không bao giờ là một ý tưởng tốt vì nó khó khăn hơn để đọc và sửa lỗi, nhưng nếu bạn là 100% chắc chắn những gì bạn đang làm, bạn chỉ có thể gọi một cái gì đó giống như set_method (R.id.button_profile_edit, "toggle_edit ") để đính kèm phương thức vào chế độ xem. Điều này rất hữu ích trong phân mảnh, nhưng một lần nữa, một số người sẽ coi nó là chống mẫu nên được cảnh báo.

public void set_method(int id, final String a_method) 
{ 
    set_listener(id, new View.OnClickListener() { 
     public void onClick(View v) { 
      try { 
       Method method = fragment.getClass().getMethod(a_method, null); 
       method.invoke(fragment, null); 
      } catch (Exception e) { 
       Debug.log_exception(e, "METHOD"); 
      } 
     } 
    }); 
} 
public void set_listener(int id, View.OnClickListener listener) 
{ 
    if (root == null) { 
     Debug.log("WARNING fragment", "root is null - listener not set"); 
     return; 
    } 
    View view = root.findViewById(id); 
    view.setOnClickListener(listener); 
} 
0

NO giao diện, NO lib, NO Java 8 cần thiết!

Chỉ cần sử dụng Callable<V> từ java.util.concurrent

public static void superMethod(String simpleParam, Callable<Void> methodParam) { 

    //your logic code [...] 

    //call methodParam 
    try { 
     methodParam.call(); 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

Làm thế nào để sử dụng nó:

superMethod("Hello world", new Callable<Void>() { 
       public Void call() { 
        myParamMethod(); 
        return null; 
       } 
      } 
    ); 

đâu myParamMethod() là phương pháp thông qua chúng tôi như là tham số (trong trường hợp này methodParam).

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