【java回調】java兩個類之間的回調函數傳遞

背景交代:熟悉用js開發的cordovaAPP;對java一竅不通的我,老師讓作一個監測用戶拍照事件的功能,無奈沒有找到現成的庫,無奈本身動手開發java插件~~0基礎java GreenHand,祝我好運T^T
本文關鍵詞:cordovaAPP插件開發、實戰問題

開發中遇到的實際問題:

存在2個只會被系統實例化的類(安卓系統事件消息硬觸發的BroadcastReceiver類,cordova觸發的CordovaPlugin類),要求將CordovaPlugin 中js傳來的callback地址傳遞到BroadcastReceiver類中。

困難1:兩個類只會被系統實例化,沒法獲取實例對象的地址,因此也就沒法實現傳統的java回調。

困難2:BroadcastReceiver類會在系統事件消息(android.hardware.action.NEW_PICTURE)產生以後觸發onReceive方法,並註銷對象以後從新生成本身的實例對象。

嘗試1:使用回調  (失敗,單純用回調)

知識:java回調

回調函數實際上就是在調用某個函數(一般是API函數)時,將本身的一個函數(這個函數爲回調函數)的地址做爲參數傳遞給那個函數。而那個函數在須要的時候,利用傳遞的地址調用回調函數,經常使用於異步獲取處理結果(耗時或處理時間不肯定的操做)。html

須要定義三個類,分別是主函數類,callback函數的接口類,耗時業務處理類,在業務處理類中,處理完業務以後,執行一個callback函數。java

文件:CallBack.java (接口)android

package com.sysnotify.lewes.sysnotify_test;

/* 建立一個callback接口
* 用於實現java回調,請仔細閱讀下面的註釋
* */
public interface CallBack {
  public void onEndcallback();
}
//用法
/*
//主函數class
public class Main {
    public static void main(String[] args) { //入口方法
        new TestCallBack().compute(1000, new ComputeCallBackFun() {

//          回調函數
            public void onComputeEnd() {
                System.out.println("end callback!!!");

            }
        });
    }
}

//耗時class
public class TestCallBack {
//耗時類中要有一個接受callback的入口函數
  public void compute(int n, CallBack callback) {
  { //執行耗時操做
     for (int i = 0; i < n; i++) {
      System.out.println(i);
    }
  }
//    執行完調用這個規定格式的callback
    callback.onEndcallback();
  }
}

*/

 

嘗試2:使用靜態變量+接口回調   (17.1.3成功)

知識:靜態變量

   類的成員變量有兩種:一種是被static關鍵字修飾的變量,叫類變量或靜態變量,一種是沒有被static修飾的,叫作實例變量 
    靜態變量和實例變量的區別在於: 
    類靜態變量在內存中只有一個,java虛擬機在加載類的過程當中爲靜態變量分配內存,靜態變量位於方法區,被類的全部實例共享,靜態變量能夠經過類名直接訪問。靜態變量的生命週期取決於類的生命週期,當類被加載的時候,靜態變量被建立並分配內存空間,當類被卸載時,靜態變量被摧毀,並釋放所佔有的內存。 
    類的每個實例都有相應的實例變量,每建立一個類的實例,java虛擬機爲實例變量分配一次內存,實例變量位於堆區中,實例變量的生命週期取決於實例的生命週期,當建立實例時,爲實例變量背建立,並分配內存,當實例被銷燬時,實例 變量被銷燬,並釋放所佔有的內存空間。 
    假如成員變量時引用變量,該成員變量結束生命週期時,並不意味着它所引用對象也結束生命週期。變量的生命週期和對象的生命週期是不一樣的概念。來源:  http://leiguomin627-126-com.iteye.com/blog/422214
 

知識:java調試信息

在調試代碼的時候咱們須要查看調試信息,那咱們就須要用Android Log類。原型Log.v(String tag, String msg)apache

android.util.Log經常使用的方法有如下5個:Log.v() Log.d() Log.i() Log.w() 以及 Log.e() 。根據首字母對應VERBOSEDEBUG,INFO, WARN,ERROR。json

一、Log.v 的調試顏色爲黑色的,任何消息都會輸出,這裏的v表明verbose囉嗦的意思,平時使用就是Log.v("","");app

二、Log.d的輸出顏色是藍色的,僅輸出debug調試的意思,但他會輸出上層的信息,過濾起來能夠經過DDMS的Logcat標籤來選擇.異步

三、Log.i的輸出爲綠色,通常提示性的消息information,它不會輸出Log.v和Log.d的信息,但會顯示i、w和e的信息ide

四、Log.w的意思爲橙色,能夠看做爲warning警告,通常須要咱們注意優化Android代碼,同時選擇它後還會輸出Log.e的信息。函數

五、Log.e爲紅色,能夠想到error錯誤,這裏僅顯示紅色的錯誤信息,這些錯誤就須要咱們認真的分析,查看棧的信息了。優化

關鍵代碼

文件:camerainfo.java (CordovaPlugin入口文件)

這裏能夠看作class A,由Cordova自動實例化,但沒法獲取其實例對象地址

package lewes;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONException;

//class A
public class camerainfo extends CordovaPlugin{
  @Override
  public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
//    註冊監聽器-拍照事件
    if("init".equals(action)){
          new CameraReceiver().setCallback(new CallBack(){
            @Override
            public void onEndcallback() {
              //在運行正確時,返回true,無傳值用.success
              //callbackContext.success();
              // 若是須要返回數值(字符串,對象等),能夠用PluginResult;
              // 若返回錯誤要改PluginResult.Status.ERROR
              PluginResult mPlugin = new PluginResult(PluginResult.Status.OK,
                "photo get!");
              mPlugin.setKeepCallback(true);
              callbackContext.sendPluginResult(mPlugin);
            }
          } );

      return true;
    }
    //傳遞消息到js 方法1 執行回調
    callbackContext.error("error");
    return false;
  }
}
文件:CameraReceiver.java & AndroidManifest.xml (系統廣播-拍照觸發後系統自動調用的函數)
這裏能夠看作 class B,由android自動實例化,但沒法獲取其實例對象地址
 
獲取拍照事件廣播的實現方法: 在AndroidManifest.xml中編輯好<receiver>,當系統消息廣播-拍照被觸發,會由安卓系統自動調用onReceive方法
詳細請了解BroadcastReceiver 的2種用法(軟監聽、硬監聽)
 
//AndroidManifest.xml  在<application>標籤內增長如下內容
  <receiver android:enabled="true" android:name="lewes.CameraReceiver">
            <intent-filter android:priority="2147483647">
                <action android:name="android.hardware.action.NEW_PICTURE" />
                <data android:mimeType="image/*" />
            </intent-filter>
 </receiver>

 //camerainfo.java 

package lewes;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

//class B
public class CameraReceiver extends BroadcastReceiver { public static CallBack cb;//關鍵是在這建立一個靜態變量,保存傳過來的callback指針
public void setCallback(CallBack callback){ cb=callback; } @Override public void onReceive(Context context, Intent intent) { cb.onEndcallback(); } }

 文件:CallBack.java (接口)

//文章開頭已給出,註釋此略
package com.sysnotify.lewes.sysnotify_test;
/* 建立一個callback接口
* */
public interface CallBack { public void onEndcallback(); }
 

 最終實現思路:java用接口(interface)來實現回調,因此首先定義一個名叫callback的接口,它有一個函數onEndCallback().

在class B 中建立一個接收callback指針的函數 setCallback(CallBack callback),一個儲存callback指針的靜態變量 public static CallBack cb

在class A 中實現接口的方法onEndCallback() (本文的這裏使用了匿名類生成接口 參見http://www.cnblogs.com/yjmyzz/p/3448330.html)

 並建立一個class B的實例,用來傳遞callback指針 new CameraReceiver().setCallback(callback指針)

最終,在class B 的接收事件產生時調用cb.onEndCallback()完成回調。

若是還沒看懂,結合代碼多看幾遍。。。。

相關文章
相關標籤/搜索