Android Tutorial - Development : Thread

 Threads Handler Demo

package com.commonsware.android.threads;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import java.util.concurrent.atomic.AtomicBoolean;

public class HandlerDemo extends Activity {
  ProgressBar bar;
  Handler handler=new Handler() {
    @Override
    public void handleMessage(Message msg) {
      bar.incrementProgressBy(5);
    }
  };
  AtomicBoolean isRunning=new AtomicBoolean(false);
  
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    bar=(ProgressBar)findViewById(R.id.progress);
  }
  
  public void onStart() {
    super.onStart();
    bar.setProgress(0);
    
    Thread background=new Thread(new Runnable() {
      public void run() {
        try {
          for (int i=0;i<20 && isRunning.get();i++) {
            Thread.sleep(1000);
            handler.sendMessage(handler.obtainMessage());
          }
        }
        catch (Throwable t) {
          // just end the background thread
        }
      }
    });
    
    isRunning.set(true);
    background.start();
  }
  
  public void onStop() {
    super.onStop();
    isRunning.set(false);
  }
}


//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
  <ProgressBar android:id="@+id/progress"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>



Using AsyncTask
/***
  Copyright (c) 2008-2009 CommonsWare, LLC
  
  Licensed under the Apache License, Version 2.0 (the "License"); you may
  not use this file except in compliance with the License. You may obtain
  a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

package com.commonsware.android.async;

import android.app.ListActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;

public class AsyncDemo extends ListActivity {
  private static String[] items={"lorem", "ipsum", "dolor",
                                  "sit", "amet", "consectetuer",
                                  "adipiscing", "elit", "morbi",
                                  "vel", "ligula", "vitae",
                                  "arcu", "aliquet", "mollis",
                                  "etiam", "vel", "erat",
                                  "placerat", "ante",
                                  "porttitor", "sodales",
                                  "pellentesque", "augue",
                                  "purus"};
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    setListAdapter(new ArrayAdapter<String>(this,
                        android.R.layout.simple_list_item_1,
                        new ArrayList()));
    
    new AddStringTask().execute();
  }
  
  class AddStringTask extends AsyncTask<Void, String, Void> {
    @Override
    protected Void doInBackground(Void... unused) {
      for (String item : items) {
        publishProgress(item);
        SystemClock.sleep(200);
      }
      
      return(null);
    }
    
    @Override
    protected void onProgressUpdate(String... item) {
      ((ArrayAdapter)getListAdapter()).add(item[0]);
    }
    
    @Override
    protected void onPostExecute(Void unused) {
      Toast
        .makeText(AsyncDemo.this, "Done!", Toast.LENGTH_SHORT)
        .show();
    }
  }
}



//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@android:id/list"
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent"
  android:drawSelectorOnTop="false"
/>
Abstract Running Thread
//package cn.edu.hit.voidmain.asmsreplier.pd_factory.threads;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public abstract class RunningThread extends Thread {
  protected Handler handler;
  
  public void setHandler(Handler handler)
  {
    this.handler = handler;
  }
  
  public Handler getHandler()
  {
    return this.handler;
  }
  
  public abstract void doWork();

  @Override
  public void run() {
    super.run();
    
    doWork();
    
    Message m = handler.obtainMessage();
    Bundle b = new Bundle();
    b.putBoolean("result", true);
    m.setData(b);
    handler.sendMessage(m);
  }

}

Sleep current thread

    

public class ServerUtils {
  
  public static void sleep(long time) {
    try {
      Thread.currentThread();
      Thread.sleep(time);
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
  }
  
  
}

Executors.newFixedThreadPool

    
//package com.myspace.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;

class MSDrawableManager {
    private final Map<String, Drawable> drawableMap;
    private ExecutorService executorService;

    static MSDrawableManager instance;
    
    static public MSDrawableManager getInstance() {
      if (instance == null) {
        synchronized(MSDrawableManager.class) {
          if (instance == null) {
            instance = new MSDrawableManager(); 
          }
        }
      }  
      return instance;
    }
    
    private MSDrawableManager() {
      drawableMap = new HashMap<String, Drawable>();
      executorService = Executors.newFixedThreadPool(2);
    }
    
    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
      if (drawableMap.containsKey(urlString)) {
        imageView.setImageDrawable(drawableMap.get(urlString));
      }
      
      imageView.setImageDrawable(null);

      final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
          imageView.setImageDrawable((Drawable) message.obj);
        }
      };

      executorService.execute(new Runnable() {
        public void run() {
          Drawable drawable = fetchDrawable(urlString);
          Message message = handler.obtainMessage(1, drawable);
          handler.sendMessage(message);
        }
      });
    }
    
    public Drawable fetchDrawable(String urlString) {
      if (drawableMap.containsKey(urlString)) {
        return drawableMap.get(urlString);
      }

      try {
        InputStream is = fetch(urlString);
        Drawable drawable = Drawable.createFromStream(is, "src");
        drawableMap.put(urlString, drawable);
        return drawable;
      } catch (Exception e) {
        return null; 
      }
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
      DefaultHttpClient httpClient = new DefaultHttpClient();
      HttpGet request = new HttpGet(urlString);
      HttpResponse response = httpClient.execute(request);
      return response.getEntity().getContent();
    }
}

Counting Thread

    
//package com.postpc.easyrider.utils;

class CountingThread extends Thread {
  private int _initialCount;
  private int _millisBetweenCount;
  private CountingListener _listener;
  private boolean _stopCounting = false;
  private boolean _hardAbort = false;
  

  public CountingThread(CountingListener listener, int initialCount, int millisBetweenCount) {
    _listener = listener;
    _initialCount = initialCount;
    _millisBetweenCount = millisBetweenCount;
  }
  
  @Override
  public void run() {
    int counter = _initialCount;
    
    _listener.onCountBegin(counter);
    
    while (!_stopCounting && counter > 0) {
      try {
        Thread.sleep(_millisBetweenCount);
      } catch (InterruptedException e) {
        // someone wants us out
        _listener.onCountAborted(counter);
        
        return;
      }
      
      counter--;
      _listener.onCount(counter);
    }
    
    if (_stopCounting) {
      if (!_hardAbort) {
        _listener.onCountAborted(counter);  
      }
    } else {
      _listener.onCountComplete();  
    }
  }

  public void abort() {
    _stopCounting = true;
    
    this.interrupt();
  }
  

  public void hardAbort() {
    _hardAbort = true;
    
    abort();
  }
}

 interface CountingListener {

  public void onCountBegin(int counter);
  

  public void onCount(int counter);

  public void onCountComplete();

  public void onCountAborted(int counter);
}

Task Queue

//package dk.itu.nai.util;

import java.util.LinkedList;

import android.util.Log;



class TaskQueue {
     private LinkedList<Runnable> tasks;
     private Thread thread;
     private boolean running;
     private Runnable internalRunnable;
     
     private final String ME = "TaskQueue";
    
     private class InternalRunnable implements Runnable {
       public void run() {
         internalRun();
       }
     }
    
     public TaskQueue() {
       tasks = new LinkedList<Runnable>();
       internalRunnable = new InternalRunnable();
     }
    
     public void start() {
       if (!running) {
         thread = new Thread(internalRunnable);
         thread.setDaemon(true);
         running = true;
         thread.start();
       }
     }
    
     public void stop() {
       running = false;
     }
   
    public void addTask(Runnable task) {
      Log.d(ME, "addTask");
       synchronized(tasks) {
           tasks.addLast(task);
           tasks.notify(); // notify any waiting threads           
       }
     }
    
     private Runnable getNextTask() {
       Log.d(ME, "getNextTask");
       synchronized(tasks) {
         if (tasks.isEmpty()) {
           try {
             tasks.wait();
           } catch (InterruptedException e) {
             Log.e(ME, "Task interrupted", e);
             stop();
           }
         }
         return tasks.removeFirst();
       }
     }
    
    
     private void internalRun() {
       while(running) {
         Runnable task = getNextTask();
         try {
           task.run();
           Thread.yield();
         } catch (Throwable t) {
           Log.e(ME, "Task threw an exception", t);
         }
       }
     }
  }

Delay Task

//package org.comet4j.core.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * ???????????????????????????????????????????????????taskId?????
 * @author xiaojinghai
 * @date 2011-7-25
 */

public class DelayTask {

  private final int cpuCoreNumber = Runtime.getRuntime().availableProcessors();
  private final ScheduledExecutorService scheduler;
  private final Map<String, ScheduledFuture<Runnable>> taskHandles = new ConcurrentHashMap<String, ScheduledFuture<Runnable>>();

  public DelayTask() {
    scheduler = Executors.newScheduledThreadPool(cpuCoreNumber);
  }

  public DelayTask(int cpuCoreNumber) {
    scheduler = Executors.newScheduledThreadPool(cpuCoreNumber);
  }



  @SuppressWarnings("unchecked")
  public void delay(String taskId, Runnable task, long delay, TimeUnit unit) {
    ScheduledFuture<Runnable> taskHandle = taskHandles.get(taskId);
    if (taskHandle == null || taskHandle.isDone()) {
      taskHandle = (ScheduledFuture<Runnable>) scheduler.schedule(task, delay, unit);
    } else {
      taskHandle.cancel(true);
      taskHandle = (ScheduledFuture<Runnable>) scheduler.schedule(task, delay, unit);
    }
    taskHandles.put(taskId, taskHandle);
  }

  /**
   * ???????????
   * @param taskId ??Id
   */

  public void cancel(String taskId) {
    ScheduledFuture<Runnable> taskHandle = taskHandles.get(taskId);
    if (taskHandle != null && !taskHandle.isDone()) {
      taskHandle.cancel(true);
    }
  }

  /**
   * ???????????
   */

  public void cancelAllTask() {
    for (String taskId : taskHandles.keySet()) {
      ScheduledFuture<Runnable> taskHandle = taskHandles.get(taskId);
      if (taskHandle != null && !taskHandle.isDone()) {
        taskHandle.cancel(true);
      }
    }
  }

  public void shutdown() {
    scheduler.shutdown();
  }

}