Message Boards Message Boards

17
|
23626 Views
|
5 Replies
|
18 Total Likes
View groups...
Share
Share this post:

Squaring a Number with the Wolfram Cloud in an Android App

Posted 11 years ago

Here, I am going to go through detailed walkthrough that will end with a fully functional Android application that can square a number given by the user. This is intended to be a tutorial for anyone who has not made a mobile app utilizing the Wolfram Cloud or is having trouble implementing that functionality into their own applications. Squaring a number is an extremely simple use of the Cloud, but this tutorial should open the way to more complex ones later on.

Creating the Cloud API

First, we need to create and deploy the API function that will be used by the app. The API will have 3 parts:

  1. Input - This is defined using an association. Here, our function will take one input, a number, and it will be refered to as "x".
  2. Function - This is a pure function that referenced the input symbol defined in (1).
  3. Output - This is the type of data we want to return. We'll just return our output as a String here.

api=APIFunction[
    {"x"->"Number"},
    #x^2&,
    "String"
];

Deploying this function is very similar to any other APIFunction. However, since we want this function accessible to our Android device, the Permissions option should be set to "Public".

(Side note: It is possible to access a private API function via a smartphone app. It is, however, more complicated, so we will put off this topic until later.)

CloudDeploy[api, Permissions->"Public"]

Evaluating this will output a hyperlink that leads to an API web form that looks like this: Cloud API form page

You can check out this form yourself by going here. Entering a number in the form and clicking "Re-send API Request" will return the square of the number you input. Alternatively, your query can be attached to the end of the url as "?x=", followed by whatever number you want to square. This is important, as this is how we will pass our number to the Cloud API within the app.

Thus, we have a working API function.

Creating an Android Application

Before digging into this section, you should be familiar with the basics of Android development. If you want to download the source code for this project, it can be downloaded here.

First, create a new Android Application containing an empty activity:

Creating the Android project

Creating an empty activity

The layout of the app will look like this:

App screenshot 1

The layout is found in res/layout/activity_main.xml and the style is in res/values-v14/styles.xml. However, for now we will focus more on the Java code that allows us to use the Wolfram Cloud. The application will have 3 Java code files: CloudInterface, CloudCompute, and MainActivity. First, let us look at CloudInterface.java.

public interface CloudInterface {
    public void onEvaluateCompleted(String result);
    public String getBaseURL();
}

The main Activity will implement this interface, allowing Cloud Compute to reference methods and data members in it. This is what will allow us to pass the result of the API call to the Main Activity and display it. Next, let us look at CloudCompute.java. This class is an AsyncTask, which allows Android to do networking tasks without stopping the rest of the application. In the first line, we can see that this AsyncTask is expecting a Double as input and will return a String. The constructor then gets the Context of MainActivty, which will allow us to pass back the result of the API call.

The doInBackground method is where the call is made. First, the URL is constructed as mentioned toward the end of the first section (using "?x=" at the end of the URL). Then a URL object is created, and an input stream is formed to receive the output of that URL. Last, an onPostExecute method is run when the doInBackground method finished. This passes the result to a method in MainActivity, which will display it.

public class CloudCompute extends AsyncTask<Double, Void, String> {
    String baseURL = "";
    CloudInterface callback;

    public CloudCompute(Context c) {
       callback = (CloudInterface) c;
       baseURL = callback.getBaseURL();
    }

    protected String doInBackground(Double... params) {

       String output = "";
       for (Double numberToBeSquared : params) {
         try {
          baseURL = baseURL + "?x=" + numberToBeSquared;

          URL url = new URL(baseURL);

          BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));

          String outLine;
          while ((outLine = in.readLine()) != null) {
              output += outLine;
          }

          in.close();

         } catch (Exception e) {
          e.printStackTrace();
         }
       }
       return output;
    }
    protected void onPostExecute(String result) {
       callback.onEvaluateCompleted(result);
    }
}

Last, we will analyze the MainActivity file. First, we need the URL of the deployed Cloud API we are using. Save this to a String variable named baseURL in the MainActivity.java file (the name is arbitrary, but this is the naming convention used across all of the sample apps we have made).
In the onCreate method, let's assign the TextView in the layout to the TextView object, then do the same to the EditText and ProgressBar.

Then, we will create a method that will be called whenever the "Square" button is clicked. First, the ProgressBar is made visible to show the user that the app is working and the previous output is cleared. Next, an InputMethodManager is used to make the keyboard disappear. Then, the contents of the field are pulled (if the field is not empty). Finally, a new instance of CloudCompute is created and executed.

Last, the onEvaluateCompleted method is run when the API call returns with a result. It makes the ProgressBar disappear and displays the result of the API call.

public class MainActivity extends Activity implements CloudInterface {
    private EditText field;
    private ProgressBar bar;
    private TextView text;

    private String baseURL = "https://www.wolframcloud.com/objects/7fd26884-806b-4801-9648-c90e175e95fa";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       field = (EditText) findViewById(R.id.field);
       bar = (ProgressBar) findViewById(R.id.progressBar);
       text = (TextView) findViewById(R.id.textView);
    }

    public void buttonClick(View v) {

       bar.setVisibility(View.VISIBLE);
       text.setText("");

       InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
       imm.hideSoftInputFromWindow(field.getWindowToken(), 0);

       Double num = 0.0;
       if(!field.getText().toString().equals(""))
         num = Double.parseDouble(field.getText().toString());

       CloudCompute cc = new CloudCompute(this);
       cc.execute(num);
    }

    @Override
    public void onEvaluateCompleted(String result) {

       bar.setVisibility(View.GONE);

       if (result.endsWith("."))
         result = result.substring(0, result.length() - 1);

       text.setText(result);
    }

    @Override
    public String getBaseURL() {
       return baseURL;
    }
}

With that, we are almost finished making an app that can use the Wolfram Cloud to make computations. To ensure that our app is allowed to make network calls, the following line must be added to the Manifest file:

<uses-permission android:name="android.permission.INTERNET"/>

And that's it! We now have an Android application that uses the Wolfram Cloud to perform a computation. Again, the code for this project can be downloaded here. This project and be imported straight into Eclipse and run on any device running Android 4.0+.

POSTED BY: Brett Haines
5 Replies

I saw in a video that Wolfram said that they will be allowing direct compiling into and APK. I sure hope that includes more than just an embed code directed at a web API. Anything that can be local should be local if at all possible. Apps that are overly dependent on the web get tons of bad ratings, which drops your rank, which drops your chances of having a successful app.

POSTED BY: David Johnston

This is very useful to see a full example like this. However, isn't there certain functions that convert directly to native java so you don't have to hit the API for stuff like this?

Having everything be an API call or an Iframe is just bad for usability. Most people have intermittent internet connections. There has to be a way to export as native java for all parts that can, the rest can be kept in the cloud. Thoughts?

POSTED BY: David Johnston

I assume this post is just an overview using a simple application to demonstrate calling the API from Android-Java. Java has Math.pow(b,e).

POSTED BY: Jesse Friedman

So ...everytime a user hits the button - i use a cloud credit ?? Is this how the system works?

POSTED BY: William Stewart

Short answer, yes.

Whenever a call is made to a Cloud API, credits are deducted from the person that deployed that API. That is to say, if you were to make and deploy an API, your personal account would be deducted credits every time your users clicked the compute button.

On the other hand, since I deployed the squaring API used in the above example, my account is deducted credits anytime someone uses it.

POSTED BY: Brett Haines
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract