Función de paso como parámetro en java
Me estoy familiarizando con el framework de Android y Java y quería crear una clase "NetworkHelper" general que manejaría la mayor parte del código de red, lo que me permitiría simplemente llamar a páginas web desde el mismo.
Seguí este artículo de developer.android.com para crear mi clase de red: http://developer.android.com/training/basics/network-ops/connecting.html
- Fire base no llama onCancelled si el tiempo de espera o no puede acceder al servidor
- Android HMAC-SHA1 Diferente de Java estándar HMAC-SHA1
- ¿Por qué se utiliza FrameLayout para fragmentos?
- Android / ORMLite Insertar fila con ID
- Unity Android Error de compilación WIN32 Excepción ZipAlign
Código:
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); } }
}
En mi clase de actividad uso la clase de esta manera:
connHelper = new NetworkHelper(this);
…
if (connHelper.checkConnection()) { //connection ok, download the webpage from provided url connHelper.downloadUrl(stringUrl); }
Problema que estoy teniendo es que de alguna manera hacer una devolución de llamada a la actividad y que debe ser definible en la función "downloadUrl ()". Por ejemplo, cuando se termina la descarga, la función public void "handleWebpage (String data)" en la actividad se llama con la cadena cargada como su parámetro.
Hice algunas google y encontré que de alguna manera debería usar interfaces para lograr esta funcionalidad. Después de revisar algunas preguntas / respuestas de stackoverflow similares, no lo hice funcionar y no estoy seguro si entendí las interfaces correctamente: ¿Cómo paso el método como un parámetro en Java? Para ser honesto usando las clases anónimas es nuevo para mí y no estoy muy seguro de dónde o cómo debo aplicar los fragmentos de código de ejemplo en el hilo mencionado.
¿Así que mi pregunta es cómo podría pasar la función de devolución de llamada a mi clase de red y llamarla después de los acabados de descarga? Donde la declaración de interfaz va, implementa la palabra clave y así sucesivamente? Observe por favor que soy principiante con Java (tenga el otro fondo de programación sin embargo) así que agradecería una explicación entera 🙂 ¡Gracias!
- Cómo convertir R.color a color?
- DrawMatching entre dos imágenes - reconocimiento de imagen
- ¿Cómo obtengo el cojinete correcto (orientación magnética) independientemente de la orientación de la pantalla?
- Socket Connection Timeout en el teléfono Android
- Android NumberFormatException: Doble no válido - excepto que el valor es un doble válido
- Excepciones de Android que manejan la mejor práctica?
- ¿Debo importar android.graphics.camera o android.hardware.camera?
- Cómo probar si un JSONObject es nulo o no existe
Utilice una interfaz de devolución de llamada o una clase abstracta con métodos de devolución de llamada abstractos.
Ejemplo de interfaz de devolución de llamada:
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... } }
La segunda opción es aún más concisa. Ni siquiera tiene que definir un método abstracto para "onDownloaded event", ya que onPostExecute
hace exactamente lo que se necesita. Simplemente extienda su DownloadWebpageTask
con una clase inline anónima dentro de su método downloadUrl
.
//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); } //...
Sí, una interfaz es la mejor manera IMHO. Por ejemplo, GWT utiliza el patrón de comandos con una interfaz como ésta:
public interface Command{ void execute(); }
De esta manera, puede pasar la función de un método a otro
public void foo(Command cmd){ ... cmd.execute(); } public void bar(){ foo(new Command(){ void execute(){ //do something } }); }
La solución fuera de la caja es que esto no es posible en Java. Java no acepta funciones de orden superior . Se puede lograr aunque por algunos "trucos". Normalmente, la interfaz es la que se utiliza como se vio. Por favor, eche un vistazo aquí para más información. También puede utilizar la reflexión para lograrlo, pero esto es propenso a errores.
El uso de interfaces puede ser la mejor manera en Java Coding Architecture.
Pero, pasar un objeto Runnable podría funcionar también, y sería mucho más práctico y flexible, creo.
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 */ } });
La reflexión nunca es una buena idea, ya que es más difícil de leer y depurar, pero si estás 100% seguro de lo que estás haciendo, simplemente puedes llamar algo como set_method (R.id.button_profile_edit, "toggle_edit") para adjuntar un método a una vista. Esto es útil en el fragmento, pero una vez más, algunas personas lo consideran como anti-patrón, así que se advirtió.
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); }
- ¿Por qué se eliminó el soporte de los Trabajadores Web HTML5 del navegador de Android en las versiones 2.2 y superiores?
- ¿Cómo se pasan las imágenes (mapas de bits) entre las actividades de androide mediante bundles?