This example shows how to run a separate process to perform a command.
We import the classes that will be needed by the application. The most relevant
to this example is the
from java.lang import ProcessBuilder, String from android.os import AsyncTask 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 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.
class ProcessActivity(Activity): __interfaces__ = [View.OnClickListener] def __init__(self): Activity.__init__(self)
The onCreate method is called when the activity is created by Android.
As with the
__init__ method, we must call the corresponding method in
the base class. We use this method to set up the user interface,
registering a listener for a button that the user can press to run a
def onCreate(self, bundle): Activity.onCreate(self, bundle) label = TextView(self) label.setText("ls -R /system") self.button = Button(self) self.button.setText("Run process") self.button.setOnClickListener(self) self.view = TextView(self) scrollView = ScrollView(self) scrollView.addView(self.view) layout = VBox(self) layout.addView(label) layout.addView(self.button) layout.addView(scrollView) self.setContentView(layout)
In the following method we respond to the button click by disabling the
button, so that the user can only start a single process, and adding a
message to the
TextView that will contain the output of the process.
def onClick(self, view): self.button.setEnabled(False) self.view.setText("Processing...") l = array(["ls", "-R", "/system"]) self.task = Task(self) self.task.execute(l)
We finish by creating a string array that we pass to the
method of a custom
When the process finishes the
Task object calls the following method to
publish the result. Here, we enable the button again and show the string
passed to the method in the
@args(void, [String]) def setResult(self, value): self.button.setEnabled(True) self.view.setText(value)
We define a Task class based on the standard AsyncTask class to monitor the background process. This defines three item types that describe the three parameters of the class: Params, Progress and Result.
class Task(AsyncTask): __item_types__ = [String, int, String]
For convenience the initialisation method accepts a reference to the activity itself, storing it for later reference, and calls the base class method as normal.
@args(void, [ProcessActivity]) def __init__(self, parent): AsyncTask.__init__(self) self.parent = parent
When the task's
execute method is called, the following method is
called in a background thread. Here, we create a background process using
the array of strings supplied in the array of
Params objects -
String in this case - and collect the output of the process in a
list of bytes.
@args(Result, [[Params]]) def doInBackground(self, params): builder = ProcessBuilder(params) builder.redirectErrorStream(True) process = builder.start() input_stream = process.getInputStream() input_bytes =  try: while True: v = input_stream.read() if v == -1: break input_bytes.add(byte(v)) except: pass process.waitFor() return String(array(input_bytes), "ASCII")
After the process has sent all its output, we wait for it to exit before
converting it to a string which we return. This value of type
delivered back to the main thread and sent to the following method.
Result is a
String in this case.
@args(void, [Result]) def onPostExecute(self, result): self.parent.setResult(result)
The method simply calls the activity's
setResult method which displays
the string in a
TextView. This is possible because the
method is itself run in the main thread.