Thursday, September 24, 2015

One way to solve the Screen Rotation problem while dealing with Android Asynctask

In many cases of Android applications employing Asynctask, the Activity that creates the Asynctask, may finish before the background job is actually done. In fact while the Asynctask is doing its job in the background, if we rotate the screen of the device, the previous Activity which created this Asynctask will be destroyed and a new instance of the same activity will be created. Hence even if the background task continues, it won't be able to update the UI, because it has already lost the connection with the previous Activity which created it. So if we were showing a ProgressDialog in the main Activity screen, it will throw runtime exception, because the Activity that created it has been already destroyed and the background task is still trying to update the previous ProgressDialog.

See the following Activity which creates an Asynctask to download an Image from a server.

package com.somitsolutions.training.android.asynctaskdownloadimage;

public class MainActivity extends Activity implements OnClickListener{
 
 Button mStartDownloadButton, mDisplayImageButton;
 EditText mURL;
 ImageView mImageView;
 private CallBack c;
 ProgressDialog mProgressDialog;
 DownloadImageAsyncTask mTask;
 Context context;
 Bitmap mBitmap;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mStartDownloadButton = (Button)findViewById(R.id.buttonDownloadImage);
  mDisplayImageButton = (Button)findViewById(R.id.buttonDisplayImage);
  mURL = (EditText)findViewById(R.id.editTextURL);
  mImageView = (ImageView)findViewById(R.id.imageView1);
  mImageView.setVisibility(View.INVISIBLE);
  mStartDownloadButton.setOnClickListener(this);
  mDisplayImageButton.setOnClickListener(this);
  
  context = this;
  
  mProgressDialog = new ProgressDialog(this);
  mProgressDialog.setMessage("On Progress...");
  mProgressDialog.setCancelable(true);
  
   c = new CallBack() {
          
    public void onProgress(){
     if(mProgressDialog == null){
      mProgressDialog = new ProgressDialog(MainActivity.this);
     mProgressDialog.setMessage("On Progress...");
     mProgressDialog.setCancelable(true);
     }
     mProgressDialog.show();  
          }
          
          public void onResult(Bitmap result){
            mBitmap = result;
            mProgressDialog.dismiss();
            Toast.makeText(context, "Done...", Toast.LENGTH_LONG).show();
            mStartDownloadButton.setEnabled(true);
            mProgressDialog = null;
           
          }
          
          public void onCancel(){
           mProgressDialog.dismiss();
           Toast toast = Toast.makeText(getApplicationContext(), "Cancelled", Toast.LENGTH_LONG);
              toast.show();
              mProgressDialog = null;
          }
         };
 }
 @Override
 public void onClick(View v) {
  // TODO Auto-generated method stub
  if (v.equals(mStartDownloadButton)){
   String URL = mURL.getText().toString();
   URL = URL.replace(" ", "");
   
   if(URL != null && !URL.isEmpty()){
    DownloadImageAsyncTask asyncTask = new DownloadImageAsyncTask(context, c);
    asyncTask.execute(URL);
    mStartDownloadButton.setEnabled(false);
   }
   
  }
  
  if(v.equals(mDisplayImageButton)){
   mImageView.setImageBitmap(mBitmap);
   mImageView.setVisibility(View.VISIBLE);
  }
 }
}

For the above Activity, if we rotate the screen when the background task is going on, the following LogCat messages will be shown:

...................
09-24 14:23:26.431: E/WindowManager(8814): android.view.WindowLeaked: Activity com.somitsolutions.training.android.asynctaskdownloadimage.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{3eded954 V.E..... R....... 0,0-639,128} that was originally added here
09-24 14:23:26.431: E/WindowManager(8814): at android.view.ViewRootImpl.(ViewRootImpl.java:363)
09-24 14:23:26.431: E/WindowManager(8814): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:271)
09-24 14:23:26.431: E/WindowManager(8814): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
09-24 14:23:26.431: E/WindowManager(8814): at android.app.Dialog.show(Dialog.java:298)
09-24 14:23:26.431: E/WindowManager(8814): at com.somitsolutions.training.android.asynctaskdownloadimage.MainActivity$1.onProgress(MainActivity.java:52)
09-24 14:23:26.431: E/WindowManager(8814): at com.somitsolutions.training.android.asynctaskdownloadimage.DownloadImageAsyncTask.onProgressUpdate(DownloadImageAsyncTask.java:37)
09-24 14:23:26.431: E/WindowManager(8814): at com.somitsolutions.training.android.asynctaskdownloadimage.DownloadImageAsyncTask.onProgressUpdate(DownloadImageAsyncTask.java:1)
09-24 14:23:26.431: E/WindowManager(8814): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:656)
09-24 14:23:26.431: E/WindowManager(8814): at android.os.Handler.dispatchMessage(Handler.java:102)
09-24 14:23:26.431: E/WindowManager(8814): at android.os.Looper.loop(Looper.java:135)
09-24 14:23:26.431: E/WindowManager(8814): at android.app.ActivityThread.main(ActivityThread.java:5254)
09-24 14:23:26.431: E/WindowManager(8814): at java.lang.reflect.Method.invoke(Native Method)
09-24 14:23:26.431: E/WindowManager(8814): at java.lang.reflect.Method.invoke(Method.java:372)
09-24 14:23:26.431: E/WindowManager(8814): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
09-24 14:23:26.431: E/WindowManager(8814): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
09-24 14:23:27.764: D/AndroidRuntime(8814): Shutting down VM
09-24 14:23:27.765: E/AndroidRuntime(8814): FATAL EXCEPTION: main
09-24 14:23:27.765: E/AndroidRuntime(8814): Process: com.somitsolutions.training.android.asynctaskdownloadimage, PID: 8814
09-24 14:23:27.765: E/AndroidRuntime(8814): java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{3eded954 V.E..... R......D 0,0-639,128} not attached to window manager
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:396)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:322)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:116)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.app.Dialog.dismissDialog(Dialog.java:341)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.app.Dialog.dismiss(Dialog.java:324)
09-24 14:23:27.765: E/AndroidRuntime(8814): at com.somitsolutions.training.android.asynctaskdownloadimage.MainActivity$1.onResult(MainActivity.java:57)
09-24 14:23:27.765: E/AndroidRuntime(8814): at com.somitsolutions.training.android.asynctaskdownloadimage.DownloadImageAsyncTask.onPostExecute(DownloadImageAsyncTask.java:42)
09-24 14:23:27.765: E/AndroidRuntime(8814): at com.somitsolutions.training.android.asynctaskdownloadimage.DownloadImageAsyncTask.onPostExecute(DownloadImageAsyncTask.java:1)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.os.AsyncTask.finish(AsyncTask.java:636)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.os.AsyncTask.access$500(AsyncTask.java:177)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.os.Handler.dispatchMessage(Handler.java:102)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.os.Looper.loop(Looper.java:135)
09-24 14:23:27.765: E/AndroidRuntime(8814): at android.app.ActivityThread.main(ActivityThread.java:5254)
09-24 14:23:27.765: E/AndroidRuntime(8814): at java.lang.reflect.Method.invoke(Native Method)
09-24 14:23:27.765: E/AndroidRuntime(8814): at java.lang.reflect.Method.invoke(Method.java:372)
09-24 14:23:27.765: E/AndroidRuntime(8814): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)

09-24 14:23:27.765: E/AndroidRuntime(8814): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

...................

One way to solve this problem is to override the onPause lifecycle method of the Activity, and inside that cancel the Background task and dismiss the ProgressDialog...

But the best way to handle this situation is to create a Fragment instead of the Activity, and inside that Fragment create the Asynctask.

Here is the code of such a fragment:

package com.somitsolutions.training.android.asynctaskdownloadimage;

import android.app.Fragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivityFragment extends Fragment implements OnClickListener{
 
 Button mStartDownloadButton, mDisplayImageButton;
 EditText mURL;
 ImageView mImageView; 
 private CallBack c;
 ProgressDialog mProgressDialog;
 DownloadImageAsyncTask mTask;
 Context context;
 Bitmap mBitmap;
 private static MainActivityFragment app;
 Boolean isScreenRotated = false;
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setRetainInstance(true);

   c = new CallBack() {
          
    public void onProgress(){
     if(c != null && !isScreenRotated){
      if(mProgressDialog == null) {
       mProgressDialog = new ProgressDialog(getActivity());
      }
      mProgressDialog.setMessage("On Progress...");
      mProgressDialog.setCancelable(true);

      mProgressDialog.show();
      }

          }
          
          public void onResult(Bitmap result){

     if (c != null && !isScreenRotated){
      mBitmap = result;

      Toast.makeText(getActivity().getApplicationContext(), "Done...", Toast.LENGTH_LONG).show();
      mStartDownloadButton.setEnabled(true);

      if(mProgressDialog != null){
       mProgressDialog.dismiss();
       mProgressDialog = null;
      }
     }
     if (isScreenRotated){
      Toast.makeText(getActivity().getApplicationContext(),"Download not completed. Please retry...", Toast.LENGTH_LONG).show();
      isScreenRotated = false;
     }
           
          }
          
          public void onCancel(){

           Toast toast = Toast.makeText(getActivity().getApplicationContext(), "Cancelled", Toast.LENGTH_LONG);
              toast.show();
     if(mProgressDialog != null){
      mProgressDialog.dismiss();
      mProgressDialog = null;
     }

          }
         };
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState){
  super.onActivityCreated(savedInstanceState);
  //isScreenRotated = false;
 }


 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

  View view = inflater.inflate(R.layout.activity_main,container,false);

  mStartDownloadButton = (Button)view.findViewById(R.id.buttonDownloadImage);
  mDisplayImageButton = (Button) view.findViewById(R.id.buttonDisplayImage);
  mURL = (EditText) view.findViewById(R.id.editTextURL);
  mImageView = (ImageView) view.findViewById(R.id.imageView1);
  mImageView.setVisibility(View.INVISIBLE);
  mStartDownloadButton.setOnClickListener(this);
  mDisplayImageButton.setOnClickListener(this);

  return view;
 }


 @Override
 public void onClick(View v) {
  // TODO Auto-generated method stub
  if (v.equals(mStartDownloadButton)){
   String URL = mURL.getText().toString();
   URL = URL.replace(" ", "");

   if(URL != null && !URL.isEmpty()){
    DownloadImageAsyncTask asyncTask = new DownloadImageAsyncTask(c);
    asyncTask.execute(URL);
    mStartDownloadButton.setEnabled(false);
   }
   
  }
  
  if(v.equals(mDisplayImageButton)){
   mImageView.setImageBitmap(mBitmap);
   mImageView.setVisibility(View.VISIBLE);
  }
 }

 @Override
 public void onDetach() {
  // All dialogs should be closed before leaving the activity in order to avoid
  // the: Activity has leaked window com.android.internal.policy... exception
  if (mProgressDialog != null && mProgressDialog.isShowing()) {
   mProgressDialog.dismiss();
   mProgressDialog = null;
  }
  if(mBitmap != null){
   mBitmap = null;

  }
  isScreenRotated = true;
  super.onDetach();
 }

 /*@Override
 public void onAttach(Activity activity){
  super.onAttach(activity);
  isScreenRotated = false;

 }*/
}


Look at the above code and see how we handle the rotation  in the Detach function (like dismissing the ProgressDialog) of the Fragment. Also important is calling setRetainInstance(true) in the onCreate method of the Fragment. Since we are calling setRetainInstance(true), the fragment won't be newly created when the screen rotates, however the Detach method will be called as usual.

And now the Activity will look like the following:

package com.somitsolutions.training.android.asynctaskdownloadimage;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

You can clone the source code of the complete App from https://github.com/sommukhopadhyay/AsynctaskDownloadImage 


Friday, September 18, 2015

Java Concurrency Model - Part III - FutureTask

Note: Get the source code from https://gitlab.com/som.mukhopadhyay/FutureTask

In the last post we have seen about CoundownLatch. In this post i will discuss about FutureTask.

Callables & Future

The FiutureTask is "A cancellable asynchronous computation. This class provides a base implementation of Future, with methods to start and cancel a computation, query to see if the computation is complete, and retrieve the result of the computation."

Callables are just like Runnables to define the smallest unit of work called tasks. The difference between Callable and Runnable is that Runnable cannot return any result whereas Callable can return result of type Future. Later we can get the data from this return value.

Once we submit the Callable task to the Executor, it does not block and returns immediately. We can determine if the task is finished or not by using the isDone api. Once isDone returns TRUE, we can access the result from the future which was returned from submitting the task to the executor using the future.get() API. However, we must remember that get API is blocking and hence if the task is not completed when the get has been called, it will block the thread.

ExecutorService
Actually FutureTask is designed to be used through the ExecutorService interface and the classes that implement it. It is those classes that use FutureTask and fork the threads and create non-blocking Asynchronous background task. Executors typically manage a pool of threads so that we don't have to create threads manually. All the threads in a thread-pool can be reused.

Class ProductInfo



package com.somitsolutions.training.java.ExperimentationWithFutureTask;

public class ProductInfo {
 
 private String productName;
 private float productPrice;
 
 public ProductInfo(String productName, float productPrice){
  this.productName = productName;
  this.productPrice = productPrice;
 }
 
 public String getProductName() {
  return productName;
 }
 public void setProductName(String productName) {
  this.productName = productName;
 }
 public float getProductPrice() {
  return productPrice;
 }
 public void setProductPrice(float productPrice) {
  this.productPrice = productPrice;
 }
 
 
}

Class Preloader

package com.somitsolutions.training.java.ExperimentationWithFutureTask;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;

public class Preloader {
 
  static ExecutorService executor  = Executors.newFixedThreadPool(1);
  List<ProductInfo> productInfo = new ArrayList<ProductInfo>();
  //The difference between Callable & Runnable 
  //is that Callable can return a value (of type futuretask)
  private FutureTask<List<ProductInfo>> future = null;
  
  /*new FutureTask>(new LoadProductInfo());*/
    
  
  public List<ProductInfo> get(){
   //List retValue = null;
   try {
    //get is blocking
    productInfo =  future.get();
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (ExecutionException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return productInfo;
  }
  
  public boolean cancel(){
   return future.cancel(true);
  }
  
  public boolean isDone(){
   return future.isDone();
  }
  
  //private final Thread thread = new Thread(future);
  
  public void start() {
   System.out.println("The task is being submitted now...");
   //submit will return immediately. So we can do the other work
   //in the main thread. Later we can check if the task is
   //finished or not using isDone method.
   future = (FutureTask<List<ProductInfo>>) (executor.submit(new LoadProductInfo())); 
   }
  
  //long running task
  private List<ProductInfo> loadProductInfo(){
   System.out.println(Thread.currentThread().getName());
   try {
    Thread.sleep(10000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   //As if this data we have got from 
   //the database
   for (int i = 0; i<100000; i++){
    ProductInfo productI = new ProductInfo(Integer.toString(i), i);
    productInfo.add(productI);
   }
   return productInfo;
  }
  //The difference between Callable & Runnable 
  //is that Callable can return a value (of type futuretask) 
  class LoadProductInfo implements Callable<List<ProductInfo>>{
 
   @Override
   public List<ProductInfo> call() throws Exception {
    // TODO Auto-generated method stub
    return loadProductInfo();
   }
   
  }
}

Class Main

package com.somitsolutions.training.java.ExperimentationWithFutureTask;

import java.util.List;

public class Main {
 public static void main(String[] args){
  List<ProductInfo> listOfProductInfo = null;
  System.out.println(Thread.currentThread().getName());
  
  Preloader preloader = new Preloader();
  
  //start getting the data in a background thread and
  //keep it for future use. while the background
  //thread is getting the data, we will continue
  //other task. later we can get this already fetched data
  //using future.get method. remember this get API is blocking
  preloader.start();
  
  /*//Do some other works... Here we are making the main thread sleep
  try {
   Thread.sleep(50000);
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }*/
  
  int count = 0;
  while (!preloader.isDone()){
   System.out.println("Task is yet to be completed...");
   count++;
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    Preloader.executor.shutdown();
    System.exit(0);
   } //sleep for 1 millisecond before checking again
   
   if (count == 100){//make the count == a low number say 8
    //to see the cancellation effect
    preloader.cancel();
    System.out.println("The task has been cancelled...");
    Preloader.executor.shutdown();
    System.exit(0);
    }
   }
  
   if(!preloader.cancel() && preloader.isDone()){
    listOfProductInfo = preloader.get();
   }
  
  System.out.println(listOfProductInfo.get(0).getProductName());
  System.out.print(listOfProductInfo.get(0).getProductPrice());
  
  Preloader.executor.shutdown();
 }
}

Java Concurrency Model - Part II - CountDownLatch

Note: Get the source code from https://github.com/sommukhopadhyay/CountDownLatche

In this post i have tried to show an example using CountDownlatch, a synchronizer in Java concurrency framework.

Class CountDownLatchTest

package com.somitsolutions.training.java.ExperimentationWithCountdownLatch;

import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CountDownLatchTest {

    public static void main(String args[]) {
       final CountDownLatch latch = new CountDownLatch(3);
       Thread service1 = new Thread(new Service("Service1", 1000, latch));
       Thread service2 = new Thread(new Service("Service2", 1000, latch));
       Thread service3 = new Thread(new Service("Service3", 1000, latch));
      
       service1.start(); 
       service2.start(); 
       service3.start();
      
       // application should not start processing any thread until all service is up
       // and ready to do there job.
       // Countdown latch is idle choice here, main thread will start with count 3
       // and wait until count reaches zero. each thread once up and read will do
       // a count down. this will ensure that main thread is not started processing
       // until all services is up.
      
       //count is 3 since we have 3 Threads (Services)
      
       try{
            latch.await();  //main thread is waiting on CountDownLatch to finish
            System.out.println("All services are up, Application is starting now");
       }catch(InterruptedException ie){
           ie.printStackTrace();
       }
      
    }
  
}

/**
 * Service class which will be executed by Thread using CountDownLatch synchronizer.
 */
class Service implements Runnable{
    private final String name;
    private final int timeToStart;
    private final CountDownLatch latch;
  
    public Service(String name, int timeToStart, CountDownLatch latch){
        this.name = name;
        this.timeToStart = timeToStart;
        this.latch = latch;
    }
  
    @Override
    public void run() {
        try {
            Thread.sleep(timeToStart);
        } catch (InterruptedException ex) {
            Logger.getLogger(Service.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println( name + " is Up");
        latch.countDown(); //reduce count of CountDownLatch by 1
    }
  
}

Java Concurrency Model - Part I - Producer Consumer Problem

Note: Get the source code from https://github.com/sommukhopadhyay/ProducerConsumer

As i was getting ready to teach Java Concurrency Model to my students, I have come up with few examples which i would like to share with you. The first example is about Producer Consumer problem. Here is the solution to this using wait and notify. In the next two posts we will see about CountDownLatch and FutureTask respectively.

Class ProducerConsumerQueue

package com.somitsolutions.training.java.ProducerConsumerProblem;

import java.util.Vector;

public class ProducerConsumerQueue {
 Vector<Integer> sharedQueue = new Vector<Integer>();
 private final int SIZE = 4;
 
 public ProducerConsumerQueue(){
 }
 
 public int getSIZE(){
  return SIZE;
 }
 
 public synchronized void produce(int i) throws InterruptedException{
  while(sharedQueue.size() == SIZE){
   System.out.println("Queue is full" + Thread.currentThread() + "is waiting, size = " + sharedQueue.size());
   wait();
  }
  sharedQueue.add(i);
  notifyAll();
 }
 
 public synchronized int consume() throws InterruptedException{
  while(sharedQueue.isEmpty()){
   
    System.out.println("Queue is empty " + Thread.currentThread().getName()
                        + " is waiting , size: " + sharedQueue.size());
    wait();
   }
  int retVal = sharedQueue.remove(0);
  notifyAll();
  return retVal;
 }
}

Class Producer

package com.somitsolutions.training.java.ProducerConsumerProblem;


public class Producer implements Runnable{
 private final ProducerConsumerQueue sharedQueue;
 private final int SIZE;
 
 public Producer(ProducerConsumerQueue queue){
  sharedQueue = queue;
  this.SIZE = sharedQueue.getSIZE();
 }
 @Override
 public void run() {
  // TODO Auto-generated method stub
  for (int i = 0; i<7; i++){
   System.out.println("Produced: " + i);
   try{
    sharedQueue.produce(i);
    Thread.sleep(100);
   }
   catch (InterruptedException ex){
    
   }
  }
 }

}

Class Consumer

package com.somitsolutions.training.java.ProducerConsumerProblem;


public class Consumer implements Runnable{
 private final ProducerConsumerQueue sharedQueue;
 private final int SIZE;
 
 public Consumer(ProducerConsumerQueue queue){
  sharedQueue = queue;
  this.SIZE = sharedQueue.getSIZE();
 }
 @Override
 public void run() {
  // TODO Auto-generated method stub
  while (true){
   try{
    int val = sharedQueue.consume();
    System.out.println("Consumed:" + val);
    Thread.sleep(50); 
   }
   catch (InterruptedException ex){ 
   }
  }
 }

}

Class Main

package com.somitsolutions.training.java.ProducerConsumerProblem;

public class Main {
 public static void main(String[] args){
  ProducerConsumerQueue sharedQueue = new ProducerConsumerQueue();
  Thread prodThread = new Thread(new Producer(sharedQueue), "Producer");
        Thread consThread = new Thread(new Consumer(sharedQueue), "Consumer");
        prodThread.start();
        consThread.start();
 }
}

Monday, August 24, 2015

UML Training...

I know , the almighty has been testing me all through my professional life... Now there is a new dilemma that is haunting me everyday. This is should i make all my training materials online for others to access free of cost or not... i believe in free flow of knowledge... hence i have made all my Google play apps open source.... For me, it does not look good to earn money by sharing knowledge... knowledge should be free... that is why i like Google because they have democratized knowledge.... however, i have not picked up any skill other than software to support my family... and not only that i like sharing knowledge with others... hence the dilemma... but i can't stop listening to my heart... hence here goes another training material and its source code...

  i believe whoever is able to follow it, does not have to come to me... however, who does not follow and can pay a little bit, will surely come to me and make it a win-win situation... the supportive source code can be cloned from

Monday, July 20, 2015

Memory layout in C++ vis-a-vis Polymorphism and Padding bits

Monday, July 13, 2015

Android Graphics & Animation - a Bouncing Ball Game with source code

Note: For my live lecture of the training on Android Graphics & Animation, please have a look at

https://youtu.be/kRqsoApOr9U

https://youtu.be/Ji84HJ85FIQ

https://youtu.be/U8igPoyrUf8

Last week while conducting the summer training on Android & Java, one guy requested me to help develop an Android game. I thought the bouncing ball would be the perfect example through which we can show about Android graphics and animation. However, i would strongly suggest to use professionals Game engines like cocos-2d to develop real life Game apps.

This app is  simple yet will be able to clarify many things related to android graphics to the students. I have made this game opensource and one can clone the source code from the following link.
https://gitlab.com/som.mukhopadhyay/BouncingBall

Here is a screen recording of this app.





If this helps the Android learners, i would probably be the happiest guy.