But before we dive into implementation details, lets quickly walk through a few important aspects when dealing with network operations.
The Main Thread and its Relation with the Network
Every time an application is launched, the system creates a thread called "main" (also know as the "UI thread"). The role of the main thread is to dispatch events to the appropriate views. Performing long operations on the main thread (like downloading a file from the internet) will block the user interface during that operation. In Android, the system guards against applications that are insufficiently responsive for a period of time by displaying a dialog that says that your app has stopped responding, offering the user an option to quit the app. I am assuming you don't want this to happen in your app.Moreover, starting with Android 3.0 (Honeycomb) and above, you are not allowed anymore to perform network operations on the main thread. Doing so will raise the famous
NetworkOnMainThreadException
.Fortunately, Android provides the AsyncTask class that can perform tasks on a separate thread.
A short intro to AsyncTask
TheAsyncTask
class enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers. In order to use it, you must extend AsyncTask and override at least 1 method, the
doInBackground()
method.However, the most common method that you will use (and are used in this tutorial) are:
1.
onPreExecute()
– called on the UI thread before the thread starts running. This method is usually used to setup the task, for example by displaying a progress bar.2.
doInBackground(Params…)
– this is the method that runs on the background thread. In this method you should put all the code you want the application to perform in background, like making the actual http request to download the image.3.
onPostExecute(Result)
– called on the UI thread after the background thread finishes. It takes as parameter the result received from doInBackground(). Usually used to update the user interface, like displaying the image that was downloaded.Example
The following code demonstrates how to use AsyncTask to download an image from the internet.1. Adding the INTERNET permission
Add the INTERNET permission to the
AndroidManifest.xml
file.<uses-permission android:name="android.permission.INTERNET" />(Also, make sure your device is actually connected to the internet, otherwise you may run into
UnknownHostException
)
2. The XML layout file
The layout file defines the
Button
that will start the download task, an ImageView
where the result will be displayed, and a ProgressBar
that will be shown while the image is downloading.Note that the
ProgressBar
is hidden by default (visibility="gone"). We will programmatically show it when the download will start and hide when the download will finish.
<RelativeLayout 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" > <Button android:id="@+id/load_image_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="6dp" android:text="@string/load_image" /> <ImageView android:id="@+id/image_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/load_image_button" android:scaleType="centerCrop" tools:ignore="ContentDescription" /> <ProgressBar android:id="@+id/progress_bar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:visibility="gone" /> </RelativeLayout>
3. The TaskListener interface
Create an interface with the following content:
public interface TaskListener { void onTaskStarted(); void onTaskFinished(Bitmap bitmap); }This interface will be used to communicate between AsyncTask and your Activity. Using an interface for communication is a good practice, as it decouples dependencies between your classes. For example you will be able to use your implementation of AsyncTask in different activities and even different projects.
onTaskStarted()
- will be called before starting the download. Here the ProgressBar
will be set as visible.void onTaskFinished(Bitmap bitmap)
- will be called when the download will finish, giving the result into a bitmap image. Here the ProgressBar
will be hidden and the image displayed.4. The ImageLoadingTask class
Create a class called
ImageLoadingTask
with the following content:public class ImageLoadingTask extends AsyncTask<String, Void, Bitmap> { private TaskListener listener; public ImageLoadingTask(TaskListener listener) { this.listener = listener; } @Override protected void onPreExecute() { listener.onTaskStarted(); } @Override protected Bitmap doInBackground(String... params) { Bitmap bitmap = null; try { URLConnection connection = new URL(params[0]).openConnection(); InputStream response = connection.getInputStream(); bitmap = BitmapFactory.decodeStream(response); } catch (IOException e) { e.printStackTrace(); } return bitmap; } @Override protected void onPostExecute(Bitmap result) { listener.onTaskFinished(result); } }
Here is what the parameterized types
AsyncTask<String, Void, Bitmap>
mean:String
- this AsyncTask will be given a String, the image url.Void
- we don't care about this one, but it is used when publishing updates to UI from the task.Bitmap
- the output, the downloaded image.The
onPreExecute()/onPostExecute()
do nothing but delegate the work to the calling activity by calling the listener methods:@Override protected void onPreExecute() { listener.onTaskStarted(); } @Override protected void onPostExecute(Bitmap result) { listener.onTaskFinished(result); }And the core job is done in
doInBackground()
:// Open the connection for the specified url URLConnection connection = new URL(params[0]).openConnection(); // Get the input stream InputStream response = connection.getInputStream(); // Create a Bitmap from the input stream bitmap = BitmapFactory.decodeStream(response);
5. The Activity class
The activity class implements the
TaskListener
interface and provides implementations for the onTasStarted()/onTaskFinished(Bitmap)
methods.Also, when the button is clicked the AsyncTask is executed.
public class NetworkPictureActivity extends ActionBarActivity implements TaskListener { private ProgressBar progressBar; private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_network_picture); progressBar = (ProgressBar) findViewById(R.id.progress_bar); imageView = (ImageView) findViewById(R.id.image_view); Button loadImageButton = (Button) findViewById(R.id.load_image_button); loadImageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { new ImageLoadingTask(NetworkPictureActivity.this) .execute("http://i.imgur.com/9gbQ7YR.jpg"); } }); } @Override public void onTaskStarted() { progressBar.setVisibility(View.VISIBLE); } @Override public void onTaskFinished(Bitmap bitmap) { progressBar.setVisibility(View.GONE); imageView.setImageBitmap(bitmap); } }
Niciun comentariu:
Trimiteți un comentariu