Java - Asynchronous and callback example

非同步(Asynchronous)呼叫廣泛應用在UI的操作上,若是UI操作上已經送出一個請求,可是當下同時又可以執行其他工作,而在建立多個非同步處理的狀態,怎麼引導某一處理在得到結果後,回到一開始執行的地方去做其他工作呢? 由於是非同步的呼叫,因此我們無法等待它完成,只能由它主動告訴主程式已經完成了,所以在此搭配callback的概念來實作這個動作!

程式範例如下:
首先定義一下請求介面,分別為成功與失敗的處理
public interface RequestMonitor {
   public void handleSuccess();
   public void handleFailure();
}

再來透過實作請求介面,定義一個可以夾帶資料的抽象請求
public class abstract DataRequestMonitor implements RequestMonitor{
   Object data;
 
   protected void setData(Object data) {
      this.data = data;
   }
 
   protected Object getData() {
      return this.data;
   }
}

緊接著是模組,也就是處理請求的人。在此為單純的讀取檔案內容,並呼叫setData將內容傳進去;若是拋出IOException的話,則呼叫setData將getMessage()傳進去!
public class Model {
   private static final Model INSTANCE = new Model();
 
   public static Model getInstance() {
      return INSTANCE;
   }
 
   public void execAsyncReadFile(final String filename, final DataRequestMonitor callback) {
      new Thread() {
         public void run() {
            try {
               callback.setData(readContents(filename));
               callback.handleSuccess();
            } catch (IOException e) {
               // TODO Auto-generated catch block
               callback.setData(e.getMessage());
               callback.handleFailure();
            }
         }
     }.start();
   }
 
   private String readContents(String filename) throws IOException {
      BufferedReader br = null;
      StringBuffer bf = new StringBuffer();
      try {
         br = new BufferedReader(new FileReader(filename));
         String line = null;
         while((line = br.readLine()) != null) {
            bf.append(line);
         }
         return bf.toString();
      }catch(IOException e) {
         throw e;
      }finally {
         if(br != null) {
            br.close();
         }
      }
   }
}

最後定義主程式,由模組呼叫execAsyncReadFile並傳進檔案位置匿名類別,請注意這裡是anonymous class extend DataRequestMonitor,因此必須override handleSuccess()及handleFailure()
。所以並沒有實體化抽象類別DataRequestMonitor!
public static void main(String[] args) {
    // TODO Auto-generated method stub
    new CallBackExample();
}
 
public CallBackExample() {
    Model model = Model.getInstance();
    String format = ".\\res\\%s.txt";
    for(int i = 0 ; i < 5 ; i++) {
       final String filename = String.format(format, i);
   
       model.execAsyncReadFile(filename, new DataRequestMonitor() {
          @Override
          public void handleSuccess() {
             // TODO Auto-generated method stub
             System.out.println("Parsing: "+filename+ " \nContents:"+getData());
          }
 
          @Override
          public void handleFailure() {
             // TODO Auto-generated method stub
             System.out.println("#Failure: "+ getData());
          }
       });
    } 
}

由於是非同步處理檔案讀取,因此在呼叫handleSuccess時可以表示檔案已經讀取完畢了!

DEMO如下:

留言