Now that the UI is in place, we need to connect the app to the backend API. There are two separate parts to this:
- Add code that gets the handle needed to access the backend API service. (All requests to the backend will use this handle.)
- Add click handlers for the UI that respond to user actions by sending requests to the backend.
Adding code to get the backend service handle
Backend API requests are made through a service handle object. Let's add a
utility method to obtain a handle to the backend service in our
AppConstants.java
.
To add code to get the backend service handle:
-
Open the file
AppConstants.java
in Android Studio. -
Replace the contents of the file with the following code:
package com.google.devrel.samples.helloendpoints; import android.app.Activity; import android.app.Dialog; import android.content.Context; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.extensions.android.json.AndroidJsonFactory; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.appspot.<your_project_id>.helloworld.Helloworld; import javax.annotation.Nullable; public class AppConstants { /** * Class instance of the JSON factory. */ public static final JsonFactory JSON_FACTORY = new AndroidJsonFactory(); /** * Class instance of the HTTP transport. */ public static final HttpTransport HTTP_TRANSPORT = AndroidHttp.newCompatibleTransport(); /** * Retrieves a Helloworld api service handle to access the API. */ public static Helloworld getApiServiceHandle() { // Use a builder to help formulate the API request. Helloworld.Builder helloWorld = new Helloworld.Builder(AppConstants.HTTP_TRANSPORT, AppConstants.JSON_FACTORY, null); return helloWorld.build(); } }
Replace the value
<your_project_id>
in the imports listed above with the actual project ID for the backend API, using Android studio's code completion. Alternatively, you can copy the actual project ID listed in the project navigator line/libs/helloworld-v1-1.17.0-rc-SNAPSHOT.jar/com.appspot.the_actual_project_id.helloworld
. -
Click File > Save All, then Build > Rebuild Project in Android Studio to make sure everything builds.
Now that we have the service handle code, let's add the click handlers for our UI.
Adding click handlers to send backend requests
Our UI needs click handlers that respond to user activity by sending the appropriate request to the backend. In this part of the tutorial, we are adding click handlers for Get Greeting, List Greetings, and Send Greetings.
Adding a click handler for Get Greeting
In this part of the UI, the user supplies the ID of the desired message in a textbox and then clicks Get Greeting to retrieve the message from the backend:
Let's add a click handler called the onClickGetGreeting
for the Get Greeting
button. We'll also need a method for displaying results that can be used by all
the other UI click handlers, which we will name displayGreetings
.
To do this:
-
Add the following code to the
MainActivity
class:/** * Implements the "Get Greeting" button. See activity_main.xml for the dynamic reference * to this method. */ public void onClickGetGreeting(View view) { View rootView = view.getRootView(); TextView greetingIdInputTV = (TextView)rootView.findViewById(R.id.greeting_id_edit_text); if (greetingIdInputTV.getText()==null || Strings.isNullOrEmpty(greetingIdInputTV.getText().toString())) { Toast.makeText(this, "Input a Greeting ID", Toast.LENGTH_SHORT).show(); return; }; String greetingIdString = greetingIdInputTV.getText().toString(); int greetingId = Integer.parseInt(greetingIdString); // Use of an anonymous class is done for sample code simplicity. {@code AsyncTasks} should be // static-inner or top-level classes to prevent memory leak issues. // @see http://goo.gl/fN1fuE @26:00 for a great explanation. AsyncTask<Integer, Void, HelloGreeting> getAndDisplayGreeting = new AsyncTask<Integer, Void, HelloGreeting> () { @Override protected HelloGreeting doInBackground(Integer... integers) { // Retrieve service handle. Helloworld apiServiceHandle = AppConstants.getApiServiceHandle(); try { GetGreeting getGreetingCommand = apiServiceHandle.greetings().getGreeting(integers[0]); HelloGreeting greeting = getGreetingCommand.execute(); return greeting; } catch (IOException e) { Log.e(LOG_TAG, "Exception during API call", e); } return null; } @Override protected void onPostExecute(HelloGreeting greeting) { if (greeting!=null) { displayGreetings(greeting); } else { Log.e(LOG_TAG, "No greetings were returned by the API."); } } }; getAndDisplayGreeting.execute(greetingId); } private void displayGreetings(HelloGreeting... greetings) { String msg; if (greetings==null || greetings.length < 1) { msg = "Greeting was not present"; Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); } else { Log.d(LOG_TAG, "Displaying " + greetings.length + " greetings."); List<HelloGreeting> greetingsList = Arrays.asList(greetings); mListAdapter.replaceData(greetings); } }
This handler checks for some user input and prompts the user to supply an ID if the user hasn't supplied one. If there is input, the integer is handed off to an AsyncTask named
getAndDisplayGreeting
, which uses the backend API service handle to make the getGreeting request to the backend.The results returned are displayed via the
displayGreetings
method shown above. -
Click File > Save All, then Build > Rebuild Project in Android Studio to make sure everything builds.
-
Test your app on Android by doing the following:
- Connect your Android device to your development system using a USB cable.
- Select Run > HelloWorld in Android Studio.
- Launch the app on your Android.
- Supply a value of
0
or1
and click Get Greeting to get the Greeting corresponding to the supplied ID.
Adding a click handler for Send Greetings
In this part of the UI, the user supplies a text message in one textbox, and an
integer N
in the other textbox. Clicking Send Greetings POSTs these
values to the backend where the greeting is repeated N
times in the response
and displayed in the ListView UI component:
To add the onClickSendGreetings
click handler for the Send Greetings button:
-
Add the following code inside the
MainActivity
class:public void onClickSendGreetings(View view) { View rootView = view.getRootView(); TextView greetingCountInputTV = (TextView)rootView.findViewById(R.id.greeting_count_edit_text); if (greetingCountInputTV.getText()==null || Strings.isNullOrEmpty(greetingCountInputTV.getText().toString())) { Toast.makeText(this, "Input a Greeting Count", Toast.LENGTH_SHORT).show(); return; }; String greetingCountString = greetingCountInputTV.getText().toString(); final int greetingCount = Integer.parseInt(greetingCountString); TextView greetingTextInputTV = (TextView)rootView.findViewById(R.id.greeting_text_edit_text); if (greetingTextInputTV.getText()==null || Strings.isNullOrEmpty(greetingTextInputTV.getText().toString())) { Toast.makeText(this, "Input a Greeting Message", Toast.LENGTH_SHORT).show(); return; }; final String greetingMessageString = greetingTextInputTV.getText().toString(); AsyncTask<Void, Void, HelloGreeting> sendGreetings = new AsyncTask<Void, Void, HelloGreeting> () { @Override protected HelloGreeting doInBackground(Void... unused) { // Retrieve service handle. Helloworld apiServiceHandle = AppConstants.getApiServiceHandle(); try { HelloGreeting greeting = new HelloGreeting(); greeting.setMessage(greetingMessageString); Multiply multiplyGreetingCommand = apiServiceHandle.greetings().multiply(greetingCount, greeting); greeting = multiplyGreetingCommand.execute(); return greeting; } catch (IOException e) { Log.e(LOG_TAG, "Exception during API call", e); } return null; } @Override protected void onPostExecute(HelloGreeting greeting) { if (greeting!=null) { displayGreetings(greeting); } else { Log.e(LOG_TAG, "No greetings were returned by the API."); } } }; sendGreetings.execute((Void)null); }
This handler invokes an AsyncTask to make the
sendGreeting
request to the backend API service. -
Click File > Save All, then Build > Rebuild Project in Android Studio to make sure everything builds.
-
Test the app as you did previously, but this time enter a text greeting in in Greeting to send textbox and an integer in the Greeting count to send textbox, then click Send Greetings. Observe the greeting multiplied by the count in the response.
At this point, your complete MainActivity
code should look like this:
package com.google.devrel.samples.helloendpoints;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.appspot.<your_project_id>.helloworld.Helloworld;
import com.appspot.<your_project_id>.helloworld.Helloworld.Greetings.GetGreeting;
import com.appspot.<your_project_id>.helloworld.Helloworld.Greetings.Multiply;
import com.appspot.<your_project_id>.helloworld.model.HelloGreeting;
import com.google.common.base.Strings;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import com.google.devrel.samples.helloendpoints.R.id;
import static com.google.devrel.samples.helloendpoints.BuildConfig.DEBUG;
public class MainActivity extends ActionBarActivity {
private static final String LOG_TAG = "MainActivity";
private GreetingsDataAdapter mListAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Prevent the keyboard from being visible upon startup.
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
ListView listView = (ListView)this.findViewById(R.id.greetings_list_view);
mListAdapter = new GreetingsDataAdapter((Application)this.getApplication());
listView.setAdapter(mListAdapter);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
/**
* Implements the "Get Greeting" button. See activity_main.xml for the dynamic reference
* to this method.
*/
public void onClickGetGreeting(View view) {
View rootView = view.getRootView();
TextView greetingIdInputTV = (TextView)rootView.findViewById(R.id.greeting_id_edit_text);
if (greetingIdInputTV.getText()==null ||
Strings.isNullOrEmpty(greetingIdInputTV.getText().toString())) {
Toast.makeText(this, "Input a Greeting ID", Toast.LENGTH_SHORT).show();
return;
};
String greetingIdString = greetingIdInputTV.getText().toString();
int greetingId = Integer.parseInt(greetingIdString);
// Use of an anonymous class is done for sample code simplicity. {@code AsyncTasks} should be
// static-inner or top-level classes to prevent memory leak issues.
// @see http://goo.gl/fN1fuE @26:00 for a great explanation.
AsyncTask<Integer, Void, HelloGreeting> getAndDisplayGreeting =
new AsyncTask<Integer, Void, HelloGreeting> () {
@Override
protected HelloGreeting doInBackground(Integer... integers) {
// Retrieve service handle.
Helloworld apiServiceHandle = AppConstants.getApiServiceHandle();
try {
GetGreeting getGreetingCommand = apiServiceHandle.greetings().getGreeting(integers[0]);
HelloGreeting greeting = getGreetingCommand.execute();
return greeting;
} catch (IOException e) {
Log.e(LOG_TAG, "Exception during API call", e);
}
return null;
}
@Override
protected void onPostExecute(HelloGreeting greeting) {
if (greeting!=null) {
displayGreetings(greeting);
} else {
Log.e(LOG_TAG, "No greetings were returned by the API.");
}
}
};
getAndDisplayGreeting.execute(greetingId);
}
private void displayGreetings(HelloGreeting... greetings) {
String msg;
if (greetings==null || greetings.length < 1) {
msg = "Greeting was not present";
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
} else {
Log.d(LOG_TAG, "Displaying " + greetings.length + " greetings.");
List<HelloGreeting> greetingsList = Arrays.asList(greetings);
mListAdapter.replaceData(greetings);
}
}
public void onClickSendGreetings(View view) {
View rootView = view.getRootView();
TextView greetingCountInputTV = (TextView)rootView.findViewById(R.id.greeting_count_edit_text);
if (greetingCountInputTV.getText()==null ||
Strings.isNullOrEmpty(greetingCountInputTV.getText().toString())) {
Toast.makeText(this, "Input a Greeting Count", Toast.LENGTH_SHORT).show();
return;
};
String greetingCountString = greetingCountInputTV.getText().toString();
final int greetingCount = Integer.parseInt(greetingCountString);
TextView greetingTextInputTV = (TextView)rootView.findViewById(R.id.greeting_text_edit_text);
if (greetingTextInputTV.getText()==null ||
Strings.isNullOrEmpty(greetingTextInputTV.getText().toString())) {
Toast.makeText(this, "Input a Greeting Message", Toast.LENGTH_SHORT).show();
return;
};
final String greetingMessageString = greetingTextInputTV.getText().toString();
AsyncTask<Void, Void, HelloGreeting> sendGreetings = new AsyncTask<Void, Void, HelloGreeting> () {
@Override
protected HelloGreeting doInBackground(Void... unused) {
// Retrieve service handle.
Helloworld apiServiceHandle = AppConstants.getApiServiceHandle();
try {
HelloGreeting greeting = new HelloGreeting();
greeting.setMessage(greetingMessageString);
Multiply multiplyGreetingCommand = apiServiceHandle.greetings().multiply(greetingCount,
greeting);
greeting = multiplyGreetingCommand.execute();
return greeting;
} catch (IOException e) {
Log.e(LOG_TAG, "Exception during API call", e);
}
return null;
}
@Override
protected void onPostExecute(HelloGreeting greeting) {
if (greeting!=null) {
displayGreetings(greeting);
} else {
Log.e(LOG_TAG, "No greetings were returned by the API.");
}
}
};
sendGreetings.execute((Void)null);
}
/**
* ArrayAdaptor that uses a static class to ensure no references to the Activity exist.
*/
static class GreetingsDataAdapter extends ArrayAdapter {
GreetingsDataAdapter(Application application) {
super(application.getApplicationContext(), android.R.layout.simple_list_item_1,
application.greetings);
}
void replaceData(HelloGreeting[] greetings) {
clear();
for (HelloGreeting greeting : greetings) {
add(greeting);
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view = (TextView)super.getView(position, convertView, parent);
HelloGreeting greeting = (HelloGreeting)this.getItem(position);
StringBuilder sb = new StringBuilder();
Set<String> fields = greeting.keySet();
boolean firstLoop = true;
for (String fieldName : fields) {
// Append next line chars to 2.. loop runs.
if (firstLoop) {
firstLoop = false;
} else {
sb.append("\n");
}
sb.append(fieldName)
.append(": ")
.append(greeting.get(fieldName));
}
view.setText(sb.toString());
return view;
}
}
}
Next...
When you are finished with these tasks, continue on to Authentication: Adding Client IDs to Backend and Library.