Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
LAB INTRODUCTION TO THE NETWORK
AND JAVA I / O
Abstract
The capability to work with the network is built-in to the Android operating system. In this lab, you will
work with several different Java and Android classes to connect to the network, make HTTP requests,
and process the responses to those requests. In this lab, you will work with the following classes:
The ConnectivityManager class is used to work with network connections.
The NetworkInfo class The HttpURLConnection class is used to connect to a resource,
such as one referenced by a URL, and get an input stream associated with that resource.
While not directly associated with the Android networking libraries, you will also work with
some of the Java I / O libraries to read data from the network. These are the same libraries used
to read and write data from and to physical files.
Key Terms
The ConnectivityManager Class
The purpose of the ConnectivityManager class is to get the state of the network and to monitor
network connections. Android provides a number of services with which you can get information about
the operating system. The following list mentions a few of the services provided:
Context.CONNECTIVITY_SERVICE returns a ConnectivityManager, which can
determine the state of the network connections.
Context.LOCATION_SERVICE returns a LocationManager used to get GPS updates
and positioning information. This service will be discussed in further detail in the location-based
programming section
Context.NETWORK_STATS_SERVICE returns a NetworkStatsManager used to query
network statistics.
The getSystemService method of the Context class is used to get a reference to one of these
services based on a constant value passed as an argument:
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
The preceding statement calls the getSystemService method of the Context class and returns an
instance of the ConnectivityManager class.
One method of the ConnectivityManager class is the getActiveNetworkInfo() which gets
information related to the currently active network. The getActiveNetworkInfo() method
returns a value having a data type of NetworkInfo.
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
The NetworkInfo class, in turn, has an accessor named isConnected. It returns true if the device
is connected to the network and false otherwise. Thus, the following statements test whether the
NetworkInfo named networkInfo exists and connected, and displays a message accordingly.
if (networkInfo != null && networkInfo.isConnected())
{
tvNetStatus.setText("Connected");
}
else
{
tvNetStatus.setText("Not Connected");
}
}
HANDS-ON ACTIVITY: Creating an additional activity:
In this sequence of steps, you will create and display a second activity just as you did in the preceding
lab.
1. Create a new project named AndroidNetworkIntro. Use the same default values that you have
been using for the project version depending on the version of your device and emulator. Create
a default activity named MainActivity as you have been doing.
2. Modify the res/values/strings.xml file so that it contains the following declarations:
<string
<string
<string
<string
<string
<string
name="app_name">AndroidNetworkIntro</string>
name="action_settings">Settings</string>
name="title_main">Android Network Intro</string>
name="title_activity_networkstatus">Network Status</string>
name="title_activity_http">HTTP Activity</string>
name="title_activity_httpresponse">HTTP Response Activity</string>
3. Modify the layout file for the main activity as follows. Note that this code contains additional
buttons that you will use later in the lab to display other forms.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidnetworkintro.MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_main" />
<Button
android:id="@+id/btnShowNetworkStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_activity_networkstatus" />
<Button
android:id="@+id/btnShowHTTP"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_activity_http" />
<Button
android:id="@+id/btnShow8HTTPResponse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_activity_httpresponse" />
</LinearLayout>
4. Create a second blank activity. Remember, to create a new activity File, New, Other to display
the following dialog box:
5. Select Android Activity to display the following dialog box:
6. In the above dialog box select Blank Activity and click Next to create the activity. Name the
activity NetworkStatusActivity. Accept the proposed changes to the project and
AndroidManifest.xml file.
7. Compile the application so that the intellisense will work with the Java “R” file.
HANDS-ON ACTIVITY: To display the network status:
In this sequence of steps, you will recreate the above code to display the status of the network. Before
doing so, however, you must modify the AndroidManifest.xml file so that the application can check the
network status and be able to use the network.
1. Modify the AndroidManfest.xml file by adding the following permission requests. The following
declarations should appear as an immediate child of the <manifest> element.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2. In these next steps, you will modify the MainActivity.java file so as to create the code that will
display the second form. Activate the src/MainActivity.java file. Create the following class at
the end of .java file that will create an intent and display the second activity. Here you are using
the technique to if implementing a class to create an event handler.
private class btnShowNetworkStatusClick implements
Button.OnClickListener
{
@Override
public void onClick(View v)
{
Intent intent = new
Intent(MainActivity.this,NetworkStatusActivity.class);
startActivity(intent);
}
}
3. Declare the following variable just after the class declaration:
private Button btnShowNetworkStatus;
4. Next, modify the onCreate() method in the main activity’s java file (src/MainActivity.java) to
register the event handler that you just created:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnShowNetworkStatus = (Button)
findViewById(R.id.btnShowNetworkStatus);
btnShowNetworkStatus.setOnClickListener(
new btnShowNetworkStatusClick());
}
5. Modify the res/layout/ActivityNetworkStatus.xml file as follows. Here, are just changing the
<RelativeLayout> to a <LinearLayout> and giving an @+id attribute to the
<TextView>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidnetworkintro.NetworkStatusActivity" >
<TextView
android:id="@+id/tvNetworkStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
6. Activate the Java file for the second activity (src/NetworkStatusActivity.Java).
7. Declare the following variable immediately after the class declaration to store a reference to the
TextView control:
private TextView tvNetworkStatus;
8. Create the following procedure at the end of the class block:
public void ShowNetworkStatus()
{
tvNetworkStatus = (TextView) findViewById(R.id.tvNetworkStatus);
// Get the status of the network.
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
// Make sure that we have a network and that the network
// is connected.
if (networkInfo != null && networkInfo.isConnected()) {
tvNetworkStatus.setText("Connected");
} else {
tvNetworkStatus.setText("Not Connected");
}
}
9. Modify the onCreate() listener adding the following statement to call the above procedure:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network_status);
ShowNetworkStatus();
}
10. Test the application and click the Network Status button. The status of the network should
appear in the second activity. If an exception is thrown, it is likely because you did not correctly
request the permissions in the AndroidManifest.xml file. Make sure the network is connected. If
it is not, the following lab steps will not work correctly.
Asynchronous Tasks
There are times when an operation uses the network that a task should be performed asynchronously.
That is, while a task is waiting on the network, the user can still interact with the user interface.
Asynchronous operations use what is called multithreading. Roughly speaking, a thread is a separate
process that communicates with the parent process. Much more can be said about multithreading and
asynchronous processing than is discussed in this lab.
Android supports a class named AsyncTask that provides a generic way to perform a task
asynchronously. AsyncTask operates by creating a background thread, and running an operation on
that background thread. The background thread, when finished, publishes the result to the User
Interface (UI) thread.
The AsyncTask processes a task using the following three steps at a minimum.
The onPreExecute() callback fires on the UI thread before the task is executed. This
callback is typically used to setup the task.
The doInBackground(Params…) callback is invoked on the background thread after the
onPreExecute() callback finished executing. The parameters to be used by the
asynchronous operation are passed in Params…
The onPostExecute(Result) callback is invoked on the UI thread after the background
operation completes. The result of the background operation is passed through the Result
parameter.
While not discussed in this tutorial, the onProgressUpdate(Progress…) and publishProgress(Progress…)
members are invoke to report the progress of a background operation.
When you use the AsyncTask, you must extend the AsyncTask class. Thus, there will always be a
class that extends AsyncTask. The following code segments shows an example of the class
declaration.
private class DownloadWebpageTask extends AsyncTask<String, Void, String>
{
}
Much of the above statements should be familiar. The code block declares a class named
DownloadWebpageTask that extends (inherits from) the AsyncTask class. However, the following
might not be familiar:
AsyncTask<String, Void, String>
The <> characters indicate that the class uses generic parameters. The purpose of these generic
parameters will become clearer in a moment.
The first parameter is used to send data to the process. In this example, a String containing
the URL will be passed to the doInBackground(String…) listener.
The second parameter is used to periodically update the progress of the background operation,
so that the user interface can be updated. In this example, the progress is not updated so the
onProgressListener() is not used. Thus, the value should be Void.
The third parameter is used to communicate the return data back to the user interface. In this
example, a string containing the results from the Web request is returned to the user interface
through the onPostExecute(Result) method.
At a minimum you must implement the doInBackground() and onPostExecute() methods as
shown in the following code block.
private class DownloadWebpageTask extends AsyncTask<String, Void, String>
{
private static final String DEBUG_TAG = "Message";
@Override
protected String doInBackground(String... urls)
{
}
@Override
protected void onPostExecute(String result)
{
}
}
The above code shows a template with which to implement an AsyncTask subclass.
In the above code block, the first generic argument to AsyncTask has a data type of String.
The doInBackground() method (listener) accepts data of type String… . The data type of
this method must match the data type of the first generic parameter of the AsyncTask class.
Note the syntax … This is a shorthand syntax indicating that the argument is an array.
The second parameter of the AsyncTask class is Void, indicating that the class will not
handle the onProgressListener() event.
The onPostExecute(Result) method (listener) accepts one argument of type string. This
argument has the same data type of the third generic parameter of the AsyncTask class.
Now that you see the implementation of an AsyncTask class, you will proceed to complete the code.
In the doInBackground() method, you will request the URL. In the onPostExecute() method,
you will get the response from the web server and display it in a text widget.
HANDS-ON ACTIVITY: To set up an asynchronous task:
In the following sequence of steps, you will create another activity, display that activity, and write the
code to set up an asynchronous task.
1. Create a new blank activity named HTTPActivity. Refer to the preceding steps to create a new
activity if you need more precise steps than those presented here.
2. Modify the code in the layout file (res/layout/activity_http) as follows. Again, you
are just changing the layout type and changing the <TextView> widget so that it fills the
window and displays multiple lines.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidnetworkintro.HTTPActivity" >
<TextView
android:id="@+id/tvHTTPResponse"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="1000"
android:singleLine="false" >
</TextView>
</LinearLayout>
3. In the MainActivity.java file, make the following changes that will display the HTTPActivity. First,
declare the class that implements the button listener as follows:
private class btnShowHTTPClick implements Button.OnClickListener
{
@Override
public void onClick(View v)
{
Intent intent = new
Intent(MainActivity.this,HTTPActivity.class);
startActivity(intent);
}
}
4. In the MainActivity.java file, write the following statement to declare a reference to the button
designated to display the second activity.
private Button btnShowNetworkStatus;
5. In the MainActivity.java file, write the following statements (shown in bold) in the
onCreate() listener to display the third activity (HTTPActivity).
btnShowNetworkStatus = (Button) findViewById(R.id.btnShowNetworkStatus);
btnShowNetworkStatus.setOnClickListener(new btnShowNetworkStatusClick());
btnShowHTTPActivity = (Button) findViewById(R.id.btnShowHTTP);
btnShowHTTPActivity.setOnClickListener(new btnShowHTTPClick());
6. In the HTTPActivity.java file, make the following additions to create the AsyncTask class. You
have not yet written the code to start the background task or make requests and process
responses.
private class DownloadWebpageTask extends AsyncTask<String, Void, String>
{
private static final String DEBUG_TAG = "Message";
@Override
protected String doInBackground(String... urls) {
return "";
}
@Override
protected void onPostExecute(String result) {
}
}
The preceding code implements the prototype for the background tasks. In the next sectionns, you will
write the code to start the background task, perform work in the background task, and finally get data
back from the background task.
Starting the Background Process
The steps to start the background process require that you test that that network is available. You
determined the status of the network and network connection earlier in this lab. If the network is
available, then you can create an instance of the AsyncTask, can then start it. Classes derived from
the AsyncTask class have a method named execute, that starts the AsyncTask. That is, is causes
the onPreExecute(), doInBackground(), and onPostExecute() methods to run as the
steps in the background process execute.
The following statements show how to create an instance of the derived AsyncTask, and then run it:
DownloadWebpageTask dw = new DownloadWebpageTask();
dw.execute("http://forecast.weather.gov/MapClick.php?lat=39.3233&lon=-120.379&"
+ "unit=0&lg=english&FcstType=dwml");
The first of the preceding statements creates in instance of the DownloadWebpageTask class, which
is derived from the AsyncTask class. So the statement creates an instance of the class that
implements the background worker. The second of the preceding statements, starts the worker by
calling the execute method. The URL is passed as an argument to the method. As you will see later in
the lab, this URL returns an XML document containing the current weather forecast for a specific
latitude and longitude.
HANDS-ON ACTIVITY: To start a background process:
In this section of the lab, you will write the code that will start the AsyncTask
(DownloadWebPageTask) class that you created. To do so, you will modify the onCreate()
callback in the HTTPActivity class to call a procedure that will start the worker process.
1. At the end of the HTTPActivity.java class, create the following procedure to test the network
status and start the background process with the URL to get the weather.
private void StartBackgroundProcess()
{
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected())
{
DownloadWebpageTask dw = new DownloadWebpageTask();
dw.execute("http://forecast.weather.gov/MapClick.php?lat=39.3233&lon=-120.379&"
+ "unit=0&lg=english&FcstType=dwml");
}
else
{
tvHTTPResponse.setText("Not Connected");
}
}
2. In the HTTPActivity.java class, write the following statement in the onCreate() callback to
execute the procedure that you just created.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_http);
StartBackgroundProcess();
}
You will not test the program yet as you have not completed the steps to request a specific URL or
process the response. That is, you have not completed the code for the AsyncTask class.
Reading Data from the Network
Now that you have seen how to determine the status of the network and start the asynchronous
process, you can proceed to open a network connection, and read data from that connection. That task
needs to be performed in the doInBackground() method of the background worker class that you
created.
Note that there are several different types of network connections. For example, it possible to make
HTTP requests and read data returned by those requests. You will use HTTP in this lab. It’s also possible
to make lower level TCP requests and use additional protocols. In summary, the network capabilities of
Android are much broader than those mentioned in this tutorial.
You worked with the URL class in previous labs when you started a browser via an implicit activity. The
URL class has other purposes too. The URL class supports a method named openConnection()
over which you can make an HTTP request and process the HTTP response. Note that other protocols
are supported too.
The openConnection() method returns an instance of the HttpURLConnection class. Using this
class instance, you can configure the connection over which the request will be send using the following
mutators:
The setConnectTimeout() mutator defines the number of milliseconds to wait to establish
a server connection.
The setReadTimeout() mutator defines the number of milliseconds to wait get a result
from the server.
The setRequestMethod() mutator defines the verb to use to make the request (GET or
POST.)
The setDoInput() allows data to be received from the request.
The following statements create a new URL. The variable myurl is assumed to contain a string and
store a valid URL. The constructor creates the URL instance. The next statements set the timeout values.
The statement conn.setRequestMethod("GET"); causes the HTTP request to be made as a GET,
request rather than a POST request. The final statement allows data to be read from the request.
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
The preceding code configures the connection. That connection is now ready to process the request.
Sending the request and getting ready to read the response involves performing the following three
steps:
Call the connect() method of the HttpURLConnection to establish a connection to the
server pointed to by the URL.
The getResponseCode() method gets the HTTP response code (404 not found, for
example).
The getInputStream() method gets a reference to the input stream associated with the
response (Web page) returned by the HTTP request. This input stream contains the data
returned by the HTTP request. In the next sequence of steps, you will see how to read the data
(XML document returned from the request.
The following code segment illustrates how to establish the connection to the server, get the response
code, and optionally, get a reference to the input stream. The Log.d call writes a message to the
LogCat system as you have seen before.
conn.connect();
int response = conn.getResponseCode();
Log.d(DEBUG_TAG, "The response is: " + response);
InputStream is = conn.getInputStream();
HANDS-ON ACTIVITY: To execute an HTTP request in a background process:
In this sequence of steps, you will write the code in the background worker process to make the HTTP
request, get the response code, and display that response code to the LogCat window (already
discussed).
1. Activate the Code Editor for the HTTPActivity.java file. Locate the doInBackground()
procedure appearing in the DownloadWebpageTask class. Modify the
doInBackground() procedure so that it contains the following code.
@Override
protected String doInBackground(String... urls) {
URL url = null;
try {
url = new URL(urls[0]);
HttpURLConnection conn = (HttpURLConnection)
url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.connect();
int response = conn.getResponseCode();
Log.d(DEBUG_TAG, "The response is: " + response);
InputStream is = conn.getInputStream();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
Most of the preceding code has been discussed already. Note that that the doInBackground
method accepts an array of URLs. So the statement url = new URL(urls[0]); parses the
first URL in the array.
Next, the connection is created and configured.
The connection (request) is made. This statement blocks until the request completes. The next
statement gets the response code and writes it to LogCat.
All of these tasks run in the background.
2. Try testing the response. You should see the response code appear in the LogCat message.
At this point, you have made the HTTP request. However, the data has not been read from the server
yet. To do so, you must read the data in the input stream. To do that, you need to understand some
basics of Java file handling:
A Bit about Java IO
Java IO is implemented such that there are several readers and writers that are layered together. These
readers and writers operate similar to the .NET StreamReader and StreamWriter classes with
which you are familiar. Some of these readers and writers are designed to work with the network.
Others are designed to work with files. Finally, others are designed to work with both files and the
network.
The InputStream class is the ancestor class of all possible byte streams. The InputStream class
has many subclasses. The InputStreamReader is designed to read a sequence of characters (a
string). In other words, the InputStreamReader converts bytes to characters.
The read() method of the InputStreamReader reads a buffer into a String. The following code
illustrates how to read a buffer into a string.
The following procedure reads an input stream into a string buffer:
First, note that the above code uses the StringBuilder class. Strings are immutable (cannot
be changed). However, we do not know the size of the input buffer (data being read from the
network). The StringBuilder class supplies an interface that allow strings to be
dynamically modified. The append() method of the StringBuilder class appends a
character to a string.
The following statements create an InputStreamReader from which the characters will be
read. Remember that the InputStreamReader is used to converts bytes to characters.. The
InputStreamReader constructor accepts the Stream as the first argument, and the
character set of the second.
The statement fragment (i = reader.read()) != -1 ) reads each character. When
there are no more characters to read, the method returns -1. The statements in the loop
convert the int to a char and append the character to the StringBuilder buffer.
The final statement in the procedure returns the string buffer.
Much more could be said about Java IO. I have provided just enough here for you to read data from the
network.
HANDS-ON ACTIVITY: To read the network buffer
You finally have what you need to implement the code that will request a URL and process the result by
displaying the XML as a simple string. In the next tutorial, you will see how parse that XML.
In the following steps you will:
Create a procedure to read the input stream.
Call the procedure from the asynchronous worker (doInBackground).
Create the code in the onPostExecute event to display the buffer. Again, in the next lab, you will
learn how to process this output.
1. In the HTTPActivity.java file, write the following code in the DownLoadWebpageTask class.
You can put the code anywhere in the class, but I suggest putting it at the end of the class. Here
you are creating the ReadIt() method just discussed.
2. In the doInBackground procedure, enter the following statements to call the procedure you
just wrote, and return the string response. This string response will be processed by the
onPostExecute method which is run on the UI thread.
InputStream is = conn.getInputStream();
// Call the procedure
String contentAsString = readIt(is);
return contentAsString;
3. Now write the following statement in the onPostExecute callback procedure to display the result
of the HTTP request.
@Override
protected void onPostExecute(String result) {
tvHTTPResponse.setText(result);
}
4. Test the application to see if everything works. If it does, you should see the XML appear in the
TextView.Fx
//15