在java中作为parameter passing函数
我对Android框架和Java很熟悉,想创build一个通用的“NetworkHelper”类,它将处理大部分的networking代码,使我可以从中调用网页。
我遵循这篇文章从developer.android.com创build我的networking类: http : //developer.android.com/training/basics/network-ops/connecting.html
码:
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); } }
}
在我的活动课中,我使用这个类:
connHelper = new NetworkHelper(this);
…
if (connHelper.checkConnection()) { //connection ok, download the webpage from provided url connHelper.downloadUrl(stringUrl); }
我遇到的问题是,我应该以某种方式callback活动,它应该可以在“downloadUrl()”函数中定义。 例如,当下载完成时,以加载的string为参数调用public void“handleWebpage(String data)”函数。
我做了一些Googlesearch,发现我应该以某种方式使用接口来实现这一function。 在回顾了几个类似的stackoverflow的问题/答案后,我没有得到它的工作,我不知道我是否正确理解接口: 如何在Java中传递方法作为参数? 说实话,使用匿名类对我来说是新的,我不确定我应该在所提到的线程中应用示例代码片断。
所以我的问题是如何将callback函数传递给我的networking类,并在下载完成后调用它? 接口声明去的地方,执行关键字等等? 请注意,我是Java的初学者(虽然有其他的编程背景),所以我会感激整个解释:)谢谢!
使用callback接口或具有抽象callback方法的抽象类。
callback界面示例:
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... } }
第二个选项更简洁。 您甚至不必为“onDownloaded事件”定义抽象方法,因为onPostExecute
完全不需要。 只需在downloadUrl
方法中使用匿名内联类来扩展您的DownloadWebpageTask
。
//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); } //...
是的,一个界面是最好的方式恕我直言。 例如,GWT使用这样的接口的命令模式:
public interface Command{ void execute(); }
这样,你就可以将一个方法的function传递给另一个方法
public void foo(Command cmd){ ... cmd.execute(); } public void bar(){ foo(new Command(){ void execute(){ //do something } }); }
开箱即用的解决scheme是,这在Java中是不可能的。 Java不接受高阶函数 。 这可以通过一些“技巧”来实现。 通常这个界面就是你所看到的界面。 请在这里看看更多的信息。 您也可以使用reflection来实现它,但是这是容易出错的。
使用接口可能是Java编码体系结构中的最佳方式。
但是,传递一个Runnable对象也可以起作用,而且我认为它会更加实用和灵活。
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 */ } });
reflection从来不是一个好主意,因为它很难读取和debugging,但是如果你100%确定你在做什么,你可以简单地调用set_method(R.id.button_profile_edit,“toggle_edit”)来附加一个方法一个看法。 这在片段中是有用的,但是又有些人会认为它是反模式,所以要警告。
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); }
没有界面,没有lib,没有Java 8需要!
只需使用java.util.concurrent
Callable<V>
public static void superMethod(String simpleParam, Callable<Void> methodParam) { //your logic code [...] //call methodParam try { methodParam.call(); } catch (Exception e) { e.printStackTrace(); } }
如何使用它:
superMethod("Hello world", new Callable<Void>() { public Void call() { myParamMethod(); return null; } } );
其中myParamMethod()
是我们传递的方法作为参数(在这种情况下是methodParam
)。