MainActivity Class

In Mobile SDK apps, the main activity begins immediately after the user logs in. Once the main activity is running, it can launch other activities, which in turn can launch sub-activities. When the application exits, it does so by terminating the main activity. All other activities terminate in a cascade from within the main activity.

The template app’s MainActivity class extends the abstract Mobile SDK activity class, com.salesforce.androidsdk.ui.SalesforceActivity. This superclass gives you free implementations of mandatory passcode and login protocols. If you use another base activity class instead, you’re responsible for implementing those protocols. MainActivity initializes the app’s UI and implements its UI buttons.

The MainActivity UI includes a list view that can show the user’s Salesforce Contacts or Accounts. When the user clicks one of these buttons, the MainActivity object performs a couple of basic queries to populate the view. For example, to fetch the user’s Contacts from Salesforce, the onFetchContactsClick() message handler sends a simple SOQL query:

Kotlin

1@Throws(UnsupportedEncodingException::class)
2
3@Suppress("UNUSED_PARAMETER")
4fun onFetchContactsClick(v: View) {
5    sendRequest("SELECT Name FROM Contact")
6}
Java

1public void onFetchContactsClick(View v) throws UnsupportedEncodingException {
2    sendRequest("SELECT Name FROM Contact");
3}

Internally, the private sendRequest() method formulates a server request using the RestRequest class and the given SOQL string:

Kotlin

1@Throws(UnsupportedEncodingException::class)
2private fun sendRequest(soql: String) {
3    val restRequest = RestRequest.getRequestForQuery(ApiVersionStrings.getVersionNumber(this), soql)
4
5    client!!.sendAsync(restRequest, object : AsyncRequestCallback {
6        override fun onSuccess(request: RestRequest, result: RestResponse) {
7            result.consumeQuietly() // consume before going back to main thread
8            runOnUiThread {
9                try {
10                    listAdapter!!.clear()
11                    val records = result.asJSONObject().getJSONArray("records")
12                    for (i in 0..records.length() - 1) {
13                        listAdapter!!.add(records.getJSONObject(i).getString("Name"))
14                    }
15                } catch (e: Exception) {
16                    onError(e)
17                }
18            }
19        }
20
21        override fun onError(exception: Exception) {
22            runOnUiThread {
23                Toast.makeText(this@MainActivity,
24                        this@MainActivity.getString(R.string.sf__generic_error, exception.toString()),
25                        Toast.LENGTH_LONG).show()
26            }
27        }
28    })
29}
Java

1private void sendRequest(String soql) throws UnsupportedEncodingException
2{
3    RestRequest restRequest =
4        RestRequest.getRequestForQuery(
5            getString(R.string.api_version), soql);
6    client.sendAsync(restRequest, new AsyncRequestCallback()
7    {
8        @Override
9        public void onSuccess(RestRequest request,
10            RestResponse result) {
11            // Consume before going back to main thread
12            result.consumeQuietly();
13            runOnUiThread(new Runnable() {
14                @Override
15                public void run() {
16                    // Network component doesn’t report app layer status.
17                    // Use the Mobile SDK RestResponse.isSuccess() method to check
18                        // whether the REST request itself succeeded.
19                    if (result.isSuccess()) {
20                        try {
21                                listAdapter.clear();
22                            JSONArray records =
23                                result.asJSONObject().getJSONArray("records");
24                            for (int i = 0; i < records.length(); i++) {
25                                listAdapter.add(
26                                    records.getJSONObject(i).getString("Name"));
27                            }
28                        } catch (Exception e) {
29                            onError(e);
30                }
31            }
32                }
33            });
34        }
35        @Override
36        public void onError(final Exception exception) {
37            runOnUiThread(new Runnable() {
38                @Override
39                public void run() {
40                    Toast.makeText(MainActivity.this,
41                        MainActivity.this.getString(R.string.sf__generic_error, exception.toString()),
42                        Toast.LENGTH_LONG).show();
43                }
44            });
45        }
46    });
47}

This method uses an instance of the com.salesforce.androidsdk.rest.RestClient class, client, to process its SOQL query. The RestClient class relies on two helper classes—RestRequest and RestResponse—to send the query and process its result. The sendRequest() method calls RestClient.sendAsync() to process the SOQL query asynchronously.

To support the sendAsync() call, the sendRequest() method constructs an instance of com.salesforce.androidsdk.rest.RestRequest, passing it the API version and the SOQL query string. The resulting object is the first argument for sendAsync(). The second argument is a callback object. When sendAsync() has finished running the query, it sends the results to this callback object. If the query is successful, the callback object uses the query results to populate a UI list control. If the query fails, the callback object displays a toast popup to display the error message.

Overriding the Default API Version 

For Android, Mobile SDK core libraries define a hard-coded default API version. This value matches the Salesforce API version on the date of the current Mobile SDK release. You can override the default version in your app by setting api_version in the strings.xml resource file.

If you override the default version, be careful when calling methods such as RestRequest.getRequestForQuery() that require an API version argument. It’s tempting to pass ApiVersionStrings.getVersionNumber(), but in some cases this call returns unexpected values. Here are some tips.

  • To return either your overridden version or the default value if no override exists, set the context argument to a valid subclass of Context. High-level subclasses include extensions of Activity, Service, and Application.
  • If you’re calling getVersionNumber() from a class that isn’t a Context subclass, you can pass SalesforceSDKManager.getInstance().getAppContext() as the context argument.
  • If you set the context argument to null, getVersionNumber() always returns the hard-coded default value.

Using an Anonymous Class in Java 

In the call to RestClient.sendAsync() the code instantiates a new AsyncRequestCallback object as its second argument. However, the AsyncRequestCallbackconstructor is followed by a code block that overrides a couple of methods: onSuccess() and onError(). If that code looks strange to you, take a moment to see what’s happening. AsyncRequestCallback is defined as an interface, so it has no implementation. In order to instantiate it, the code implements the two AsyncRequestCallback methods inline to create an anonymous class object. This technique gives TemplateApp a sendAsync() implementation of its own that can never be called from another object and doesn’t litter the API landscape with a group of specialized class names.

We've Moved

Welcome to the new home of the Mobile SDK Developer Guide! For now, the Japanese guide can be found in PDF form.