Passing function as a parameter in java

后端 未结 6 970
南笙
南笙 2020-11-28 22:13

I\'m getting familiar with Android framework and Java and wanted to create a general \"NetworkHelper\" class which would handle most of the networking code enabling me to ju

相关标签:
6条回答
  • 2020-11-28 22:30

    Use a callback interface or an abstract class with abstract callback methods.

    Callback interface example:

    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...
        }
    }
    

    The second option is even more concise. You do not even have to define an abstract method for "onDownloaded event" as onPostExecute does exactly what is needed. Simply extend your DownloadWebpageTask with an anonymous inline class inside your downloadUrl method.

        //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);
        }
    
        //...
    
    0 讨论(0)
  • 2020-11-28 22:30

    The out of the box solution is that this is not possible in Java. Java does not accept Higher-order functions. It can be achieved though by some "tricks". Normally the interface is the one used as you saw. Please take a look here for further information. You can also use reflection to achieve it, but this is error prone.

    0 讨论(0)
  • 2020-11-28 22:35

    Yes, an interface is the best way IMHO. For example, GWT uses the command pattern with an interface like this:

    public interface Command{
        void execute();
    }
    

    In this way, you can pass function from a method to another

    public void foo(Command cmd){
      ...
      cmd.execute();
    }
    
    public void bar(){
      foo(new Command(){
         void execute(){
            //do something
         }
      });
    }
    
    0 讨论(0)
  • 2020-11-28 22:37

    Using Interfaces may be the best way in Java Coding Architecture.

    But, passing a Runnable object could work as well, and it would be much more practical and flexible, I think.

     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 */
       }
    });
    
    0 讨论(0)
  • 2020-11-28 22:41

    NO interface, NO lib, NO Java 8 needed!

    Just using Callable<V> from 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();
        }
    }
    

    How to use it:

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

    Where myParamMethod() is our passed method as parameter (in this case methodParam).

    0 讨论(0)
  • 2020-11-28 22:56

    Reflection is never a good idea since it's harder to read and debug, but if you are 100% sure what you're doing, you can simply call something like set_method(R.id.button_profile_edit, "toggle_edit") to attach a method to a view. This is useful in fragment, but again, some people would consider it as anti-pattern so be warned.

    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 讨论(0)
提交回复
热议问题