Download presentation
Presentation is loading. Please wait.
1
CS499 – Mobile Application Development
Fall 2013 Threads & Android – Part 2
2
Concurrent Programming
Carnegie Mellon Concurrent Programming Multiple processes – each logical control flow is a process. Some form of IPC (InterProcess Communication) needed Multiple threads – multiple logical control flows within a single process. Shared address space I/O multiplexing – event driven concurrency. Shared address space
3
Android Threads Activities have a main thread – the UI thread
App components in the same process use the same main thread User interaction, system callback & lifecycle methods are handled in the UI thread It is essential that the UI remains responsive UI toolkit not thread-safe. A piece of code is thread-safe if it only manipulates shared data structures in a manner that guarantees safe execution by multiple threads at the same time.
4
Implications Two rules:
Do not block the UI thread Blocking the UI thread hurts responsiveness Long-running operations should be done in background thread Don’t access/manipulate the UI toolkit from a non UI thread. Results are unpredictable Q: How can the UI & background threads communicate in a thread-safe manner?
5
Consider the following Game App:
public class Demo extends Activity { int public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.demo); final View root – findViewById(R.id.root); final Drawable bg = root.getBackground(); final TextView msg = (TextView) findViewById(R.id.msg); final Game game = Game.newGame(); ((Button)findViewById(R.id.start)).setOnClickListener( new View.onClickListener() public void onClick(View v) { // initialize the game! } } });
6
Want to display animated background while waiting to initialize…
// Broken – do not use!!! void initGame(View root, Drawable bg, Game game, TextView resp, String level) { // if animation hasn’t started, make it start if (0 >= mInFlight++) { root.setBackgroundResource(R.anim.dots); ((AnimationDrawable)root.getBackground()).start(); } // initialize the game String msg = game.initialize(level); // if last initialization remove & clean up animation if (0 >= --mInFlight) { ((AnimationDrawable)root.getBackground()).stop(); root.setBackgroundDrawable(bg); resp.setText(msg);
7
Problem: UI thread is executing game
Problem: UI thread is executing game.initialize and hence can’t show the animation background animation won’t work if the initialize takes too long, the android framework will suspend it
8
Might be tempted to do the following:
public void onClick(View v) { new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork(" mImageView.setImageBitmap(b); } }).start(); } Seems to meet Rule 1 but violates Rule 2
9
Solution: AsyncTask Structured, safe, powerful, and easy-to-use way to manage UI and background threads correctly. Generic class class AsyncTask<Params,Progress,Result> { … } Generic type parameters Params – Types used in background work Progress – Types used when indicating progress Result – Types of result
10
AsyncTask methods Runs before doInBackground() Performs work
void onPreExecute() Runs before doInBackground() Result doInBackground(Params… params) Performs work can call void publishProgress(Progress…values) void onProgressUpdate(Progress…values) Invoked in response to publishProgress() void onPostExecute(Result result) Runs after doInBackground()
11
public void onClick(View v) { new DownloadImageTask()
public void onClick(View v) { new DownloadImageTask().execute(" } private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { /** The system calls this to perform work in a worker thread and * delivers it the parameters given to AsyncTask.execute() */ protected Bitmap doInBackground(String... urls) { return loadImageFromNetwork(urls[0]); } /** The system calls this to perform work in the UI thread and delivers * the result from doInBackground() */ protected void onPostExecute(Bitmap result) { mImageView.setImageBitmap(result); } }
12
AsyncTask Created on UI thread. When ‘execute’d
UI thread invokes onPreExecute() to do any setup UI thread creates new background thread that runs a doInBackground() method concurrently Once background thread terminates, onPostExecute() is run in the UI thread.
13
public void onCreate(Bundle state) { super
public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.main); final View dots = findViewById(R.id.dots); final Drawable bg = dots.getBackground(); final TextView msg = ((TextView) findViewById(R.id.msg)); final Game game = Game.newGame(); ((Button) findViewById(R.id.start)).setOnClickListener( new View.OnClickListener() { public void onClick(View v) { new AsyncInitGame(dots, bg, game,msg).execute("basic"); } }); }
14
private final class AsyncInitGame extends AsyncTask<String, Void, String> { private final View root; private final Game game; private final TextView message; private final Drawable bg; public AsyncInitGame(View root, Drawable bg, Game game, TextView msg) { this.root = root; this.bg = bg; this.game = game; this. message = msg; } // runs on the UI protected void onPreExecute() { if (0 >= mInFlight++) { root.setBackgroundResource(R.anim.dots); ((AnimationDrawable)root.getBackground()).start();
15
// runs on the UI protected void onPostExecute(String msg) { if (0 >= --mInFlight) { ((AnimationDrawable)root.getBackground()).stop(); root.setBackgroundDrawable(bg); } message.setText(msg); // runs on a background protected String doInBackground(String … args) { return ((1 != args.length) || (null == args[0])) ? null : game.initialize(args[0]);
16
AsyncTask dataflow Creation Thread (UI) New Thread execute(args…)
doInBackground(args…) : result doPostExecute(result)
17
private final class LoadIconTask extends Integer,Integer,Bitmap> { protected Bitmap doInBackground(Integer…resid) { Bitmap tmp = BitmapFactory.decodeResource( getResources(),resid[0]); for (int I = 1; i< 11;i++) { // some long running op… publishProgress(i*10); } return tmp; protected void onProgressUpdate(Integer... values) { progress.setProgress(values[0]); protected void onPostExecute(Bitmap result) { iview.setImageBitmap(result); }
18
Be careful! UI thread should not modify data sent as parameters to AsyncTasks doInBackground() must only make thread-safe references to variables inherited into its scope. int mCount; public void initButton(Button button) { mCount = 0; new View.OnClickListener() { @Override public void onClick(View v) { new AsyncTask<Void,Void,Void>() { @Override protected Void doInBackground(Void…args) { mCount++; // NOT THREAD SAFE return null; } }.execute(); } });
19
However… Beginning with Honeycomb (3.0), Android changed how it's running the AsyncTasks: AsyncTask task = new AsyncTask1(); if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { task.execute(); }
20
Handler Threads can also communicate by posting Messages & Runnables to a Handler Message Can contain a code, data object & args Recipient (Handler) implements response Runnable Contains an instance of the Runnable interface Sender implements response
21
Handler sendMessage() post() Looper Puts Message on MessageQueue
Puts runnable on Message Queue Looper One per Thread Dispatches MessageQueue entries Calls handleMessage() for Messages Calls run() for Runnables
22
Simple use of UI handler
public void onClick(View v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadImageFromNetwork(" mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bitmap); } }); } }).start(); }
23
Handler Two main uses for a Handler
Schedule Message/Runnable for future execution Enqueue action to be performed on a different thread
24
Messages & Handlers Create Message and set Message content
Handler.obtainMessage() Message.obtain() Many variants. See documentation Message parameters include int arg1, arg2 int what Object obj Bundle data
25
Messages & Handlers sendMessage() sendMessageAtFrontOfQueue()
Queue message immediately sendMessageAtFrontOfQueue() Insert message immediately at front ofqueue SendMessageAtTime() Queue message at the stated time sendMessageDelayed() Queue message after the stated delay
26
public class SimpleThreadingExample extends Activity { private final static int SET_PROGRESS_BAR_VISIBILITY = 0; private final static int PROGRESS_UPDATE = 1; private final static int SET_BITMAP = 2; private ImageView iview; private ProgressBar progress; Handler handler = new Handler() public void handleMessage(Message msg) { switch (msg.what) { case SET_PROGRESS_BAR_VISIBILITY: { progress.setVisibility((Integer) msg.obj); break; } case PROGRESS_UPDATE: { progress.setProgress((Integer) msg.obj); case SET_BITMAP: { iview.setImageBitmap((Bitmap) msg.obj); }; …
27
@Override public void onCreate(Bundle savedInstanceState) { super
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); iview = (ImageView) findViewById(R.id.imageView1); progress = (ProgressBar) findViewById(R.id.progressBar1); final Button button = (Button) findViewById(R.id.loadButton); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { new Thread(new LoadIconTask(R.drawable.icon, handler)).start(); } });
28
private class LoadIconTask implements Runnable { private final int resId; private final Handler handler; LoadIconTask(int resId, Handler handler) { this.resId = resId; this.handler = handler; } public void run() { final Bitmap tmp = BitmapFactory.decodeResource(getResources(), resId); Message msg = null; msg = handler.obtainMessage(SET_PROGRESS_BAR_VISIBILITY,ProgressBar.VISIBLE); handler.sendMessage(msg); for (int i = 1; i < 11; i++) { sleep(); msg = handler.obtainMessage(PROGRESS_UPDATE, i * 10); } msg = handler.obtainMessage(SET_BITMAP, tmp); msg = handler.obtainMessage(SET_PROGRESS_BAR_VISIBILITY, ProgressBar.INVISIBLE); private void sleep() { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace();}
29
Runnables & Handlers boolean post(Runnable r)
Add Runnable to the MessageQueue boolean postAtTime(Runnable r, long uptimeMillis) Add Runnable to the MessageQueue. Run at a specific time (based on SystemClock.upTimeMillis()) boolean postDelayed(Runnable, long delayMillis) Add Runnable to the message queue. Run after the specified amount of time elapses.
30
public class SimpleThreadingExample extends Activity { private ImageView iview; private final Handler handler = new public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); iview = (ImageView) findViewById(R.id.imageView1); final Button button = (Button) findViewById(R.id.loadButton); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { new Thread(new LoadIconTask(R.drawable.icon)).start();} }); } private class LoadIconTask implements Runnable { int resId; LoadIconTask(int resId) { this.resId = resId; } public void run() { final Bitmap tmp = BitmapFactory.decodeResource(getResources(),resId); handler.post(new Runnable() { public void run() { iview.setImageBitmap(tmp);} }}
31
public class SimpleThreadingExample extends Activity { private Bitmap public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final ImageView iview = (ImageView) findViewById(R.id.imageView1); final Button button = (Button) findViewById(R.id.loadButton); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { new Thread(new Runnable() { public void run() { bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.icon); iview.post(new Runnable() { public void run() { iview.setImageBitmap(bitmap); } });} }).start(); });
32
public class SimpleThreadingExample extends Activity { private Bitmap public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final ImageView iview = (ImageView) findViewById(R.id.imageView1); final Button button = (Button) findViewById(R.id.loadButton); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { new Thread(new Runnable() { public void run() { bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon); SimpleThreadingExample.this.runOnUiThread(new Runnable() { iview.setImageBitmap(bitmap); } }); }).start();
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.