【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函數)時,將自己的一個函數(這個函數為回調函數)的地址作為參數傳遞給那個函數。而那個函數在需要的時候,利用傳遞的地址調用回調函數,常用於異步獲取處理結果(耗時或處理時間不確定的操作)。

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

文件:CallBack.java (接口)

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)

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

1、Log.v 的調試顏色為黑色的,任何消息都會輸出,這里的v代表verbose啰嗦的意思,平時使用就是Log.v("","");

2、Log.d的輸出顏色是藍色的,僅輸出debug調試的意思,但他會輸出上層的信息,過濾起來可以通過DDMS的Logcat標簽來選擇.

3、Log.i的輸出為綠色,一般提示性的消息information,它不會輸出Log.v和Log.d的信息,但會顯示i、w和e的信息

4、Log.w的意思為橙色,可以看作為warning警告,一般需要我們注意優化Android代碼,同時選擇它后還會輸出Log.e的信息。

5、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()完成回調。

如果還沒看懂,結合代碼多看幾遍。。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM