1. 程式人生 > >java中的回撥CallBack,Thread以及與android的關聯

java中的回撥CallBack,Thread以及與android的關聯

  • class A實現介面InA 
  • class A中包含一個class B的引用b
  • class B有一個引數為InA的方法test(InA a) 
  • A的物件a呼叫B的方法傳入自己,test(a) ——這一步相當於you call me
  • 然後b就可以在test方法中呼叫InA的方法 ——這一步相當於i call you back
這是回撥的基本含義,大家可以看一下的程式碼,首先先定義一個介面CallBack,唯一的方法是solve():
再來定義實現了CallBack介面的class A,定義為Boss類,我們模擬的場景是,Boss手下有一個員工Employee,Boss在某個時刻想要讓員工去幫他買東西,當員工買完後將把結果告知給Boss,也就是我們所說的回撥,通過回撥函式的solve()方法將結果給Boss。

Boss類在建立的時候需要傳入一個員工物件Employee,在需要的時候,會呼叫Employee的方法,讓他來處理邏輯,Employee如下:
當想要呼叫Employee的buySomething方法時,需要傳入Callback介面的實現類,邏輯處理完畢後則呼叫Callback介面的方法回傳結果,編寫測試類,測試結果如下:

其實在Java中,執行緒Thread的原理也是使用了回撥機制,我們可以來看下面這個最簡單的執行緒例項:
new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				
			}
		}).start();
我們先進入Runnable程式碼中去看,可以發現他是個介面:
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

我們將Runnable的實現類當做引數傳入給Thread類,Thread的start()方法會回撥Runnable實體類的run方法來進行邏輯處理,但是我們卻發現了一個奇怪的事情,那就是Thread類已經實現了Runnable介面,卻還要傳入Runnable的實現類,這是為什麼?原來這是java中的代理模式!!!

繼承Thread類方式和通過Runnable介面的方式

   繼承Thread類方式的缺點:如果我們的類已經繼承了其他類,那就無法再繼承Thread類了

   實現Runnable介面的方式優點:避免了單繼承,方便共享資源,同一份資源可以有多個代理訪問

代理就比如是找房子可以找中介,結婚可以找婚慶公司。

   在靜態代理模式中有兩個角色

  1:真實角色

  2:代理角色

   兩個角色通過實現相同的介面來實現關聯

下面可以看一個例子:
//真實角色  
class You implements IMarry{  
  
    @Override  
    public void marry() {  
    }  
}  
代理角色
class WeddingCompany implements  IMarry{  
  
    @Override  
    public void marry() {  
  
    }  
}  

讓代理模式持有真實角色的引用

class WeddingCompany implements IMarry {  
    private IMarry you;  
    public WeddingCompany(){}  
    public WeddingCompany(IMarry you){  
        this.you=you;  
    }  
    @Override  
    public void marry() {  
        you.marry();  
    }  
}  
使用例項程式碼
public static void main(String[] args) {  
     //建立真實角色  
     IMarry you=new You();  
     //建立代理角色加入真實角色的引用  
     WeddingCompany weddingCompany=new WeddingCompany(you);  
 }  


此時讓我們進入Thread的建構函式來去看看:
public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

繼續往下找,就能看到初始化Runnable物件的程式碼(中間省略):
  private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
...
 this.target = target;
        setPriority(priority);
...
    }
好了,我們可以看到Thread的建構函式將Runnable的例項物件初始化給了成員變數,我們都知道要啟動一個執行緒需要呼叫start()方法,我們看下start()方法做了什麼:
public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
具體程式碼不做研究,start()方法呼叫作業系統本地的執行緒啟動方法,使得run()方法內部的程式碼執行在非同步執行緒中,我們都知道執行緒啟動有兩種方法,start()和run(),start方法正常啟動非同步執行緒,而run方法雖然同樣執行了內部的所有操作,但確實跟主執行緒同步執行的,無法進行非同步操作,我們看下Thread的run方法就知道為什麼了:
/**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

這樣我們就能看出所以然了,Thread的run方法居然只是簡單地呼叫了傳入的Runnable物件的run方法,並沒有開啟非同步執行緒。 關於Thread的幾種常用方式可以看下網上的部落格,一般都是兩種方法:直接繼承Thread重寫run方法或者實現Runnable介面寫run方法,兩種區別就是,實現Runnable介面適用於多執行緒對於同一個資料進行操作,例如我們常見的賣票系統等。
本篇主要是說回撥的使用,有些跑偏了,那麼android中是否存在回撥呢? 必須得啊,我們天天都在使用的OnClickListener,OnLongClickListener等一系列方法都是回撥方法,首先我們看下回調介面:
/**
     * Interface definition for a callback to be invoked when a view is clicked.
     */
    public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }

對,沒錯,就是View類中的OnClickListener介面,這個介面唯一的方法:onClick也就是回撥函式用於我們處理點選事件的邏輯,當一個View發生點選事件時,就會回撥onClick方法,我們就可以在Activity進行邏輯處理。下面我們模擬一下這個場景,首先定義抽象介面和view如下:
//點選事件的介面
		public interface OnClickListener {
			public void onclick();
		}
	//view類,儲存實現事件介面的實體物件,在適當的時候呼叫介面方法,回傳點選事件
	public class View{
		private  OnClickListener listener;
		public void performClick(){
			listener.onclick();
		}
		public void SetOnClickListener(OnClickListener l){
			listener=l;
		}
	}
實際情況中OnClickListener是定義在View類的內部,但這裡我們為了更好地看清楚回撥函式的使用,將其分開來了。View中定義了兩個方法,SetOnClickListener用來將onClickListener的例項物件與其繫結,也就是獲得例項物件,當用戶進行點選操作時performClick方法就會被呼叫,然後回撥介面的onclick方法。 下面是Activity的定義:
//Activity實現點選事件的介面,用來接收view的點選事件
	public class Activity implements OnClickListener{
		private View view;
		public Activity(){
			view=new View();
			view.SetOnClickListener(this);
		}
		public void onclick(){
			System.out.println("view點選一次");
		}
		public void clickOnce(){
			view.performClick();
		}
	}

Activity實現了介面OnClickListener,並定義了一個view,呼叫view的SetOnClickListener方法將自己傳入,然後我們模擬點選事件,clickOnce呼叫時,就會呼叫view的performClick方法,然後view會回撥onclick(),如下:
/**
	 * @param args
	 */
	public static void main(String[] args) {
		Activity activity=new MyActivity().new Activity();
		activity.clickOnce();
	}



當然我們只是非常簡單地模擬點選事件,不過原理就是我們上面所講述的:回撥!!!可見回撥在程式設計中是非常重要的一個知識點。在android開發中要結合java的特性來思考,以前只會簡單地呼叫view.setOnClickListener(),不明白其中的原理,現在一定要多想多思考。

相關推薦

javaCallBackThread以及android關聯

class A實現介面InA class A中包含一個class B的引用bclass B有一個引數為InA的方法test(InA a) A的物件a呼叫B的方法傳入自己,test(a) ——這一步相當於you call me然後b就可以在test方法中呼叫InA的方法 —

關於對Java函式的理解

先來看幾段程式: 1.  首先定義一個類Caller,這個類裡面儲存一個介面引用。        public class Caller {     private MyCallInter

函式函式指標函式物件

1.  什麼是回撥函式     回撥函式(callback Function),顧名思義,用於回撥的函式。  回撥函式只是一個功能片段,由使用者按照回撥函式呼叫約定來實現的一個函式。回撥函式是一個工作流的一部分,由工作流來決定函式的呼叫(回撥)時機。回撥函 數包含下面

java原理以及Callable和FutureTask通過機制建立可監控的執行緒

回撥的概念會JS的人應該都能理解。 回撥分非同步回撥,同步回撥。但是同步回撥其實沒什麼意義。都同步了,那麼直接等那邊執行完了,這邊再執行就可以了,沒必要通過回撥。我們說的回撥主要是講非同步回撥。用於兩個執行緒甚至兩個系統之間互動呼叫。 例如我在A類的方法funa()中,要呼叫B類的方法fun

安卓(Android)如何優雅的 建立/執行 非同步任務/(AsyncTask 、Thread、Job、CallBack、Handler) ?執行緒池(Executor)

How to use? 1、first step: copy the file "ExcuteTaskManager" and "ExcuteTask" to your project 2、second step: init the library in your application or

Java執行緒之非同步(Callback)

●介紹      有時候執行一個任務需要很長時間,單執行緒下執行緒會處於阻塞狀態。這個時候我們會考慮一種非阻塞的處理模式。非阻塞任務在任何程式語言裡都必不可少,Java也不例外。多執行緒就是一個很好的解決辦法。     

C++ | callback函式函式名做引數傳遞

 在js中的回撥函式已經是隨處可見了,像下面這樣 // js callback demo function foo(value){ console.log(value) } function inject(callback){ var value = 'hello!

Java程式設計之委託代理、內部類以及匿名內部類(閉包)

最近一直在看Java的相關東西,因為我們在iOS開發是,無論是Objective-C還是Swift中,經常會用到委託代理回撥,以及Block回撥或者說是閉包回撥。接下來我們就來看看Java語言中是如何實現委託代理回撥以及閉包回撥的。當然這兩個技術點雖然實現起來並不困難,但是,這回調在封裝一些公用元件時還是特別

vue使用函式this呼叫無效

let self = this //使用新變數替換this,以免this無效//updateStudentInfoToServer是一個將本身部分資料非同步上傳的介面,this.updateStudentInfoToServer(data,   function(res){ 

java繼承的理解super關鍵字方法的重寫和過載以及注意事項理解

一、類的繼承理解 在java中類的繼承是指:在一個現有類的基礎之上去構建一個新的類,構建出來的新的類被稱為子類,現有類是父類,子類會自動擁有父類所有可繼承的屬性和方法。繼承類是現有類的更具體一些,繼承類可能只擁有一部分父類的屬性和方法。 如圖,這就表示了繼承類是父類的一種更具體形式

android網路程式設計使用java機制

1) 先定義一個介面 public interface HttpCallbackListener { void onFinish(String response); void onError(Exception e); } 2) 在工具類HttpUtil中

Zookeeper Java API (三) zk節點的通知(Watcher)和(CallBack)

Zk中的通知(Watcher) ZooKeeper中實現對接點的監控,需要實現Watcher介面類,實現其中的process方法 public class WatcherDemo implements Watcher{ public void p

Android ndk jnijava的方法&欄位描述符

一、jobject和jclass 1.如果定義native方法時使用了static關鍵字,那麼生成的標頭檔案裡就會傳入jclass,代表這個類的引用。 2.如果沒有使用static關鍵字,那麼就會傳入jobject,代表類的物件的引用。 二、jni回撥

Android finish()自動時機Activity資源釋放邏輯放在onDestroy一定合適嗎

首先看Google對finish()的描述, Call this when your activity is done and should be closed. The ActivityResult is propagated back

JAVA函式和反射機制(原理不說直接看程式碼)補充動靜態代理

程式碼都是轉載或抄錄這個地址: http://blog.csdn.net/zhandoushi1982/article/details/8567709 http://blog.csdn.net/xiaanming/article/details/8703708/ 反射機制

Android介面總結以及運用到彈窗PopWindow的Demo實現

背景: 最近專案中接觸到介面回撥,以及Android彈窗PopWindow元件的使用,現在利用學到的知識自己寫了一個簡單的Demo,練習下在Android下如何運用介面回撥,來實現彈窗PopWindow的功能。 程式碼結構: 1. 定義一個介面:OnSelectIt

面試官問我“Java的鎖有哪些?以及區別”我跪了

讀寫鎖 queue get 吞吐量 參考 示例 事情 自動 高並發 在讀很多並發文章中,會提及各種各樣鎖如公平鎖,樂觀鎖等等,這篇文章介紹各種鎖的分類。介紹的內容如下: 公平鎖/非公平鎖 可重入鎖 獨享鎖/共享鎖 互斥鎖/讀寫鎖 樂觀鎖/悲觀鎖 分段鎖 偏

javajsp的EL的定義以及使用

eve ext ges tar lis 簡易 resp 必須 xpath 1、定義: EL(Expression Language) 是為了使JSP寫起來更加簡單。表達式語言的靈感來自於 ECMAScript 和 XPath 表達式語言,它提供了在 JSP 中簡化表

在drawRect:方法繪制圖片文字以及Core Graphics 框架的了解

graphic csg line 要求 arc 畫圖 cgrect 有一個 get p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000 } p.p2 { margin: 0.0

java常見的類接口異常

tex 權限 array 變量 都是 run 做的 pointer 數組下標                       java中常見的類,接口,包,異常 類   String  Integer  Long   File   Date  Thread(java.lang.