Class Loader Method Call Example

This example shows how to find and load a class from a library and call its methods.

A screenshot of the application.

We import the classes that will be needed by the application. The most relevant to this example is the ClassLoader class.

from java.lang import Boolean, Class, ClassLoader, ClassNotFoundException, \
                      Long, NoSuchMethodException, Object, String
from java.lang.reflect import Method
from android.view import View
from android.widget import Button, ScrollView, TextView
from serpentine.activities import Activity
from serpentine.widgets import VBox

We define a class based on a custom Activity class provided by the serpentine package. This represents the application, and will be used to present a graphical interface to the user.

The class declares the use of the View.OnClickListener interface so that it can respond to button clicks. It also declares a field, method, that will contain a reference to the method that will be called when the user clicks the button; initially this is undefined.

class MethodCallActivity(Activity):

    __interfaces__ = [View.OnClickListener]
    __fields__ = {"method": Method}
    
    CLASS = "android.os.Vibrator"
    CHECK_METHOD = "hasVibrator"
    METHOD = "vibrate"
    DURATION = 500 # ms

We define the names of the class and two of its methods that we wish to call, as well as an argument that we will pass to the second method.

The initialisation method simply calls the corresponding method in the base class. This must be done even if no other code is included in the method.

    def __init__(self):
    
        Activity.__init__(self)

We use the onCreate method to set up the user interface which consists of a label, showing the method name, and a button for executing the method.

    def onCreate(self, bundle):
    
        Activity.onCreate(self, bundle)
        
        label = TextView(self)
        label.setText(self.CLASS)
        
        self.button = Button(self)
        self.button.setText(self.METHOD)
        self.button.setOnClickListener(self)
        
        layout = VBox(self)
        layout.addView(label)
        layout.addView(self.button)
        
        self.setContentView(layout)
        
        self.getClassAndMethod()

We finish the initialisation by calling a method to obtain information about the class and its method that we want to call.

The method called is given below. We begin by obtaining an instance of the class whose method we will call and initialising the method field defined earlier.

    def getClassAndMethod(self):
    
        self.vibrator = self.getSystemService(self.VIBRATOR_SERVICE)
        self.method = None

In a try...except structure we load the class and query it for the methods we want to call. The first, hasVibrator, returns a boolean value that is presented to us as a "boxed" Boolean value.

        try:
            cl = self.vibrator.getClass()
            
            hasVibrator = cl.getMethod(self.CHECK_METHOD, array(Class, 0))
            
            result = hasVibrator.invoke(self.vibrator, array(Object, 0))
            if not CAST(result, Boolean).booleanValue():
                self.button.setEnabled(False)
                return

If the result of the method call is False then we disable the button and return. Otherwise, we can proceed by obtaining a Method object that represents the vibrate method, updating the button's text if successful.

            self.method = cl.getMethod(self.METHOD, array([Long.TYPE]))
            self.button.setText("Invoke " + self.METHOD + "(" + str(self.DURATION) + ")")
        
        except NoSuchMethodException, e:
            self.button.setEnabled(False)

If either of the methods are not found then we disable the button to prevent the user from clicking it since there is no suitable method to invoke.

Only if the button is enabled can the following method be called. In it, we invoke the method stored in the method field with the required arguments: a long value supplied as a "boxed" Long instance.

    def onClick(self, view):
    
        try:
            self.method.invoke(self.vibrator, array([Long(self.DURATION)]))
        except:
            pass

The invocation can fail with a variety of exceptions so we simply catch all of them in a single clause.

Files