Android反射機制實現與原理

来源:http://www.cnblogs.com/wumingchen/archive/2016/08/17/5781844.html
-Advertisement-
Play Games

本文介紹Android反射機制實現與原理,在介紹之前,要和Java進行比較,所以先看下Java中的反射相關知識: 一、反射的概念及在Java中的類反射 反射主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力。在電腦科學領域,反射是一類應用,它們能夠自描述和自控制。這類應用通過某種機制來實現 ...


本文介紹Android反射機制實現與原理,在介紹之前,要和Java進行比較,所以先看下Java中的反射相關知識:

一、反射的概念及在Java中的類反射

  反射主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力。在電腦科學領域,反射是一類應用,它們能夠自描述和自控制。這類應用通過某種機制來實現對自己行為的描述和檢測,並能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義。

   在Java中的反射機制,被稱為Reflection(大家看到這個單詞,第一個想法應該就是去開發文檔中搜一下了)。它允許運行中的Java程式對自身進行檢查,並能直接操作程式的內部屬性或方法。Reflection機制允許程式在正在執行的過程中,利用Reflection APIs取得任何已知名稱的類的內部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,並可以在執行的過程中,動態生成Instances、變更fields內容或喚起methods

  好,瞭解這些,那我們就知道了,我們可以利用反射機制在Java程式中,動態的去調用一些protected甚至是private的方法或類,這樣可以很大程度上滿足我們的一些比較特殊需求。你當然會問,反射機制在Android平臺下有何用處呢?

  我們在進行Android程式的開發時,為了方便調試程式,並快速定位程式的錯誤點,會從網上下載到對應版本的Android SDK的源碼(這裡給大家提供一個2.3.3版本的下載鏈接)。你會發現很多類或方法中經常加上了“@hide”註釋標記,它的作用是使這個方法或類在生成SDK時不可見,那麼我們的程式可能無法編譯通過,而且在最終發佈的時候,就可能存在一些問題。

  那麼,對於這個問題,第一種方法就是自己去掉Android源碼中的"@hide"標記,然後重新編譯生成一個SDK。另一種方法就是使用Java反射機制了,可以利用這種反射機制訪問存在訪問許可權的方法或修改其域。

  廢話半天,該入正題了,在進入正題之前,先給上一個反射測試類的代碼,該代碼中定義了我們需要進行反射的類,該類並沒有實際的用途,僅供做為測試類。提示:本文提供的代碼,並不是Android平臺下的代碼,而是一個普通的Java程式,僅僅是對Java反射機制的Demo程式,所以大家不要放在Android下編譯啊,否則出現問題,別追究我的責任啦!

 1 ReflectionTest.java
 2 package crazypebble.reflectiontest;
 3 
 4 import java.awt.event.ActionEvent;
 5 import java.awt.event.ActionListener;
 6 import java.io.Serializable;
 7 
 8 public class ReflectionTest extends Object implements ActionListener,Serializable{
 9     // 成員變數
10     private int bInt;
11     public Integer bInteger = new Integer(4);
12     public String strB = "crazypebble";
13     private String strA;
14     
15     // 構造函數
16     public ReflectionTest() {
17         
18     }
19     
20     protected ReflectionTest(int id, String name) { 
21         
22     }
23     
24     // 成員方法
25     public int abc(int id, String name) {
26         System.out.println("crazypebble ---> " + id + "-" + name);
27         return 0;
28     }
29     
30     protected static void edf() {
31         
32     }
33     
34     @Override
35     public void actionPerformed(ActionEvent e) {
36         // TODO Auto-generated method stub
37         
38     }
39     
40 }

 

二、反射機制中需要使用到的類

  我把需要使用的類列在下表中,其中對我們特別有用的類,通過著重標記顯示出來,並將在後面的使用中逐步解釋:

Android反射機制實現與原理 - Nelson - Nelson

 

三、Class

  首先向大家說明一點,Class本身就是一個類,Class是該類的名稱。看下麵這個類的定義:

  public class MyButton extends Button {...}

   註意到上面的class的首字母是小寫,它表示的是一種類類型,但是我們的Class是一個類,相當於上面定義的MyButton類。所以,千萬不要把這裡的Class做為一個類類型來理解。明白這一點,我們繼續。

  Class類是整個Java反射機制的源頭,Class類本身表示Java對象的類型,我們可通過一個Object對象的getClass()方法取得一個對象的類型,此函數返回的就是一個Class類。獲取Class對象的方法有很多種:

Android反射機制實現與原理 - Nelson - Nelson

  在平時的使用,要註意對這幾種方法的靈活運用,尤其是對Class.forName()方法的使用。因為在很多開發中,會直接通過類的名稱取得Class類的對象。

 

四、獲取類的相關信息

1、獲取構造方法

  Class類提供了四個public方法,用於獲取某個類的構造方法。

    Constructor getConstructor(Class[] params)     根據構造函數的參數,返回一個具體的具有public屬性的構造函數

    Constructor getConstructors()     返回所有具有public屬性的構造函數數組

    Constructor getDeclaredConstructor(Class[] params)     根據構造函數的參數,返回一個具體的構造函數(不分public和非public屬性)

    Constructor getDeclaredConstructors()    返回該類中所有的構造函數數組(不分public和非public屬性)

  由於Java語言是一種面向對象的語言,具有多態的性質,那麼我們可以通過構造方法的參數列表的不同,來調用不同的構造方法去創建類的實例。同樣,獲取不同的構造方法的信息,也需要提供與之對應的參數類型信息;因此,就產生了以上四種不同的獲取構造方法的方式。

 1 get_Reflection_Constructors()
 2     /**
 3      * 獲取反射類中的構造方法
 4      * 輸出列印格式:"Modifier修飾域   構造方法名(參數類型列表)"
 5      */
 6     public static void get_Reflection_Constructors(ReflectionTest r) {
 7         
 8         Class temp = r.getClass();
 9         String className = temp.getName();        // 獲取指定類的類名
10         
11         try {
12             Constructor[] theConstructors = temp.getDeclaredConstructors();           // 獲取指定類的公有構造方法
13             
14             for (int i = 0; i < theConstructors.length; i++) {
15                 int mod = theConstructors[i].getModifiers();    // 輸出修飾域和方法名稱
16                 System.out.print(Modifier.toString(mod) + " " + className + "(");
17 
18                 Class[] parameterTypes = theConstructors[i].getParameterTypes();       // 獲取指定構造方法的參數的集合
19                 for (int j = 0; j < parameterTypes.length; j++) {    // 輸出列印參數列表
20                     System.out.print(parameterTypes[j].getName());
21                     if (parameterTypes.length > j+1) {
22                         System.out.print(", ");
23                     }
24                 }
25                 System.out.println(")");
26             }
27         } catch (Exception e) {
28             e.printStackTrace();
29         }
30     }

2、獲取類的成員方法

  與獲取構造方法的方式相同,存在四種獲取成員方法的方式。

    Method getMethod(String name, Class[] params)    根據方法名和參數,返回一個具體的具有public屬性的方法

    Method[] getMethods()    返回所有具有public屬性的方法數組

    Method getDeclaredMethod(String name, Class[] params)    根據方法名和參數,返回一個具體的方法(不分public和非public屬性)

    Method[] getDeclaredMethods()    返回該類中的所有的方法數組(不分public和非public屬性)

 1 get_Reflection_Method()
 2     /**
 3      * 獲取反射類的方法
 4      * 列印輸出格式:"RetType FuncName(paramTypeList)"
 5      */
 6     public static void get_Reflection_Method(ReflectionTest r) {
 7         
 8         Class temp = r.getClass();
 9         String className = temp.getName();
10         
11         /*
12          * Note: 方法getDeclaredMethods()只能獲取到由當前類定義的所有方法,不能獲取從父類繼承的方法
13          * 方法getMethods() 不僅能獲取到當前類定義的public方法,也能得到從父類繼承和已經實現介面的public方法
14          * 請查閱開發文檔對這兩個方法的詳細描述。
15          */
16         //Method[] methods = temp.getDeclaredMethods();
17         Method[] methods = temp.getMethods();
18         
19         for (int i = 0; i < methods.length; i++) {
20             
21             // 列印輸出方法的修飾域
22             int mod = methods[i].getModifiers();
23             System.out.print(Modifier.toString(mod) + " ");
24             
25             // 輸出方法的返回類型
26             System.out.print(methods[i].getReturnType().getName());    
27             
28             // 獲取輸出的方法名
29             System.out.print(" " + methods[i].getName() + "(");
30             
31             // 列印輸出方法的參數列表
32             Class[] parameterTypes = methods[i].getParameterTypes();
33             for (int j = 0; j < parameterTypes.length; j++) {
34                 System.out.print(parameterTypes[j].getName());
35                 if (parameterTypes.length > j+1) {
36                     System.out.print(", ");
37                 }
38             }
39             System.out.println(")");
40         }
41     }

在獲取類的成員方法時,有一個地方值得大家註意,就是getMethods()方法和getDeclaredMethods()方法。

    getMethods():用於獲取類的所有的public修飾域的成員方法,包括從父類繼承的public方法和實現介面的public方法;

    getDeclaredMethods():用於獲取在當前類中定義的所有的成員方法和實現的介面方法,不包括從父類繼承的方法。

  大家可以查考一下開發文檔的解釋:

 getMethods() - Returns an array containing Method objects for all public methods for the class C represented by this Class.  Methods may be declared in C, the interfaces it implements or in the superclasses of C. The elements in the returned array are in no particular order. 

 getDeclaredMethods() - Returns a Method object which represents the method matching the specified name and parameter types that is declared by the class represented by this Class. 

  因此在示例代碼的方法get_Reflection_Method(...)中,ReflectionTest類繼承了Object類,實現了actionPerformed方法,並定義如下成員方法:

     Android反射機制實現與原理 - Nelson - Nelson

  通過這兩個語句執行後的結果不同:

  a、Method[] methods = temp.getDeclaredMethods()執行後結果如下:

    Android反射機制實現與原理 - Nelson - Nelson

  b、Method[] methods = temp.getMethods()執行後,結果如下:

     Android反射機制實現與原理 - Nelson - Nelson

3、獲取類的成員變數(成員屬性)

  存在四種獲取成員屬性的方法

    Field getField(String name)    根據變數名,返回一個具體的具有public屬性的成員變數

    Field[] getFields()    返回具有public屬性的成員變數的數組

    Field getDeclaredField(String name)    根據變數名,返回一個成員變數(不分public和非public屬性)

    Field[] getDelcaredField()    返回所有成員變數組成的數組(不分public和非public屬性)

 1 get_Reflection_Field_Value()
 2     /**
 3      * 獲取反射類中的屬性和屬性值
 4      * 輸出列印格式:"Modifier Type : Name = Value"
 5      * Note: 對於未初始化的指針類型的屬性,將不輸出結果
 6      */
 7     public static void get_Reflection_Field_Value(ReflectionTest r) {
 8         
 9         Class temp = r.getClass();    // 獲取Class類的對象的方法之一
10         
11         try {
12             System.out.println("public 屬性");
13             Field[] fb = temp.getFields();
14             for (int i = 0; i < fb.length; i++) {
15                 
16                 Class cl = fb[i].getType();    // 屬性的類型
17                 
18                 int md = fb[i].getModifiers();    // 屬性的修飾域
19                 
20                 Field f = temp.getField(fb[i].getName());    // 屬性的值
21                 f.setAccessible(true);
22                 Object value = (Object)f.get(r);
23                 
24                 // 判斷屬性是否被初始化
25                 if (value == null) {
26                     System.out.println(Modifier.toString(md) + " " + cl + " : "      + fb[i].getName());
27                 }
28                 else {
29                     System.out.println(Modifier.toString(md) + " " + cl + " : "      + fb[i].getName() + " = " + value.toString());
30                 }
31             }
32             
33             System.out.println("public & 非public 屬性");
34             Field[] fa = temp.getDeclaredFields();
35             for (int i = 0; i < fa.length; i++) {
36                 
37                 Class cl = fa[i].getType();    // 屬性的類型
38                 
39                 int md = fa[i].getModifiers();    // 屬性的修飾域
40                 
41                 Field f = temp.getDeclaredField(fa[i].getName());    // 屬性的值
42                 f.setAccessible(true);    // Very Important
43                 Object value = (Object) f.get(r);
44                 
45                 if (value == null) {
46                     System.out.println(Modifier.toString(md) + " " + cl + " : "      + fa[i].getName());
47                 }
48                 else {
49                     System.out.println(Modifier.toString(md) + " " + cl + " : "  + fa[i].getName() + " = " + value.toString());
50                 }
51             }
52         } catch (Exception e) {
53             e.printStackTrace();
54         }
55     }

4、獲取類、屬性、方法的修飾域

  類ClassMethodConstructorField都有一個public方法int getModifiers()。該方法返回一個int類型的數,表示被修飾對象( Class、 Method、 Constructor、 Field )的修飾類型的組合值。

  在開發文檔中,可以查閱到,Modifier類中定義了若幹特定的修飾域,每個修飾域都是一個固定的int數值,列表如下:

    Android反射機制實現與原理 - Nelson - Nelson

  該類不僅提供了若幹用於判斷是否擁有某中修飾域的方法boolean isXXXXX(int modifiers),還提供一個String toString(int modifier)方法,用於將一個表示修飾域組合值的int數轉換成描述修飾域的字元串。

    Android反射機制實現與原理 - Nelson - Nelson

 

五、如何調用類中的private方法

  在介紹之前,先放一個代碼吧,這段代碼是參考其他文章的代碼拷貝過來的,代碼不算長,但是動態調用類的成員方法的過程講解的通俗易懂。

  1 LoadMethod.java
  2 package crazypebble.reflectiontest;
  3 
  4 import java.lang.reflect.Constructor;
  5 import java.lang.reflect.Method;
  6 
  7 
  8 public class LoadMethod {
  9 
 10     /**
 11      * 在運行時載入指定的類,並調用指定的方法
 12      * @param cName            Java的類名
 13      * @param MethodName    方法名
 14      * @param types            方法的參數類型
 15      * @param params        方法的參數值
 16      * @return
 17      */
 18     public Object Load(String cName, String MethodName, String[] types, String[] params) {
 19         
 20         Object retObject = null;
 21         
 22         try {
 23             // 載入指定的類
 24             Class cls = Class.forName(cName);    // 獲取Class類的對象的方法之二
 25             
 26             // 利用newInstance()方法,獲取構造方法的實例
 27             // Class的newInstance方法只提供預設無參構造實例
 28             // Constructor的newInstance方法提供帶參的構造實例
 29             Constructor ct = cls.getConstructor(null);
 30             Object obj = ct.newInstance(null);    
 31             //Object obj = cls.newInstance();
 32             
 33             // 構建 方法的參數類型
 34             Class paramTypes[] = this.getMethodTypesClass(types);
 35             
 36             // 在指定類中獲取指定的方法
 37             Method meth = cls.getMethod(MethodName, paramTypes);
 38             
 39             // 構建 方法的參數值
 40             Object argList[] = this.getMethodParamObject(types, params);
 41             
 42             // 調用指定的方法並獲取返回值為Object類型
 43             retObject = meth.invoke(obj, argList);
 44             
 45         } catch (Exception e) {
 46             System.err.println(e);
 47         }
 48         
 49         return retObject;
 50     }
 51     
 52     /**
 53      * 獲取參數類型,返回值保存在Class[]中
 54      */
 55     public Class[] getMethodTypesClass(String[] types) {
 56         Class[] cs = new Class[types.length];
 57         
 58         for (int i = 0; i < cs.length; i++) {
 59             if (types[i] != null || !types[i].trim().equals("")) {
 60                 if (types[i].equals("int") || types[i].equals("Integer")) {
 61                     cs[i] = Integer.TYPE;
 62                 } 
 63                 else if (types[i].equals("float") || types[i].equals("Float")) {
 64                     cs[i] = Float.TYPE;
 65                 }
 66                 else if (types[i].equals("double") || types[i].equals("Double")) {
 67                     cs[i] = Double.TYPE;
 68                 }
 69                 else if (types[i].equals("boolean") || types[i].equals("Boolean")) {
 70                     cs[i] = Boolean.TYPE;
 71                 }
 72                 else {
 73                     cs[i] = String.class;
 74                 }
 75             }
 76         }
 77         return cs;
 78     }
 79     
 80     /**
 81      * 獲取參數Object[]
 82      */
 83     public Object[] getMethodParamObject(String[] types, String[] params) {
 84         
 85         Object[] retObjects = new Object[params.length];
 86     
 87         for (int i = 0; i < retObjects.length; i++) {
 88             if(!params[i].trim().equals("")||params[i]!=null){  
 89                 if(types[i].equals("int")||types[i].equals("Integer")){  
 90                     retObjects[i]= new Integer(params[i]);  
 91                 }
 92                 else if(types[i].equals("float")||types[i].equals("Float")){  
 93                     retObjects[i]= new Float(params[i]);  
 94                 }
 95                 else if(types[i].equals("double")||types[i].equals("Double")){  
 96                     retObjects[i]= new Double(params[i]);  
 97                 }
 98                 else if(types[i].equals("boolean")||types[i].equals("Boolean")){  
 99                     retObjects[i]=new Boolean(params[i]);  
100                 }
101                 else{  
102                     retObjects[i] = params[i];  
103                 }  
104             } 
105         }
106         
107         return retObjects;
108     }
109 }

要調用一個類的方法,首先需要一個該類的實例(當然,如果該類是static,就不需要實例了,至於原因,你懂得!)。

1、創建一個類的實例

  在得到一個類的Class對象之後,我們可以利用類Constructor去實例化該對象。Constructor支持泛型,也就是它本身應該是Constructor<T>。這個類有一個public成員函數:T newInstance(Object... args),其中args為對應的參數,我們通過Constructor的這個方法來創建類的對象實例。

  在代碼LoadMethod.javaLoadMethodEx.java中,分別給出了兩種實例化Class類的方法:一種是利用Constructor類調用newInstance()方法;另一種就是利用Class類本身的newInstance()方法創建一個實例。兩種方法實現的效果是一樣的。

 1 // 利用newInstance()方法,獲取構造方法的實例
 2 
 3 // Class的newInstance方法,僅提供預設無參的實例化方法,類似於無參的構造方法
 4 
 5 // Constructor的newInstance方法,提供了帶參數的實例化方法,類似於含參的構造方法 
 6 
 7 Constructor ct = cls.getConstructor(null);
 8 
 9 Object obj = ct.newInstance(null);
10 
11 Object obj = cls.newInstance();

2、行為

  Method類中包含著類的成員方法的信息。在Method類中有一個public成員函數:Object invoke(Object receiver, Object... args),參數receiver指明瞭調用對象,參數args指明瞭該方法所需要接收的參數。由於我們是在運行時動態的調用類的方法,無法提前知道該類的參數類型和返回值類型,所以傳入的參數的類型是Object,返回的類型也是Object。(因為Object類是所有其他類的父類)

  如果某一個方法是Java類的靜態方法,那麼Object receiver參數可以傳入null,因為靜態方法從不屬於對象。

 3、屬性

  對類的成員變數進行讀寫,在Field類中有兩個public方法:

    Object get(Object object),該方法可用於獲取某成員變數的值

    Void set(Object object, Object value),該方法設置某成員變數的值

  其中,Object參數是需要傳入的對象;如果成員變數是靜態屬性,在object可傳入null

 

六、對LoadMethod.java的優化處理

  在上一節中給出的LoadMethod.java中,類LoadMethod對固定參數類型的方法進行了調用,並且參數類型是通過一個String[]數組傳入,然後經過方法 getMethodTypesClass() 解析之後,才得到了參數的具體的類型。同時在getMethodTypesClass()getMethodParamObject()方法中,通過對傳入的字元串參數進行過濾後,再處理那些可以匹配中的參數類型,其他不能匹配的參數都做為String對象來處理。如果我們調用的方法所需要的參數不是簡單類型的變數,而是自定義的類對象,或者List列表,再如果我們只知道類名和方法名,不知道方法的參數類型,那我們該如何處理這些情況呢?

  因此,我對LoadMethod類進行了一定的優化處理。先附上代碼:

 1 LoadMethodEx.java
 2 package crazypebble.reflectiontest;
 3 
 4 import java.lang.reflect.Constructor;
 5 import java.lang.reflect.Method;
 6 
 7 
 8 public class LoadMethodEx {
 9 
10     /**
11      * 在運行時載入指定的類,並調用指定的方法
12      * @param cName            Java的類名
13      * @param MethodName    方法名
14      * @param params        方法的參數值
15      * @return
16      */
17     public Object Load(String cName, String MethodName, Object[] params) {
18         
19         Object retObject = null;
20         
21         try {
22             // 載入指定的類
23             Class cls = Class.forName(cName);    // 獲取Class類的對象的方法之二
24             
25             // 利用newInstance()方法,獲取構造方法的實例
26             // Class的newInstance方法只提供預設無參構造實例
27             // Constructor的newInstance方法提供帶參的構造實例
28             Constructor ct = cls.getConstructor(null);
29             Object obj = ct.newInstance(null);    
30             //Object obj = cls.newInstance();
31 
32             // 根據方法名獲取指定方法的參數類型列表
33             Class paramTypes[] = this.getParamTypes(cls, MethodName);
34             
35             // 獲取指定方法
36             Method meth = cls.getMethod(MethodName, paramTypes);
37             meth.setAccessible(true);
38             
39             // 調用指定的方法並獲取返回值為Object類型
40             retObject = meth.invoke(obj, params);
41             
42         } catch (Exception e) {
43             System.err.println(e);
44         }
45         
46         return retObject;
47     }
48     
49     /**
50      * 獲取參數類型,返回值保存在Class[]中
51      */
52     public Class[] getParamTypes(Class cls, String mName) {
53         Class[] cs = null;
54         
55         /*
56          * Note: 由於我們一般通過反射機制調用的方法,是非public方法
57          * 所以在此處使用了getDeclaredMethods()方法
58          */
59         Method[] mtd = cls.getDeclaredMethods();    
60         for (int i = 0; i < mtd.length; i++) {
61             if (!mtd[i].getName().equals(mName)) {    // 不是我們需要的參數,則進入下一次迴圈
62                 continue;
63             }
64             
65             cs = mtd[i].getParameterTypes();
66         }
67         return cs;
68     }
69 }

 我們通過前面幾節的一系列分析,只要我們知道了一個類的類名(包括其包的路徑),那我們就可以通過Class類的一系列方法,得到該類的成員變數、構造方法、成員方法、以及成員方法的參數類型和返回類型、還有修飾域等信息。

  如果我們已經知道某個類名和需要動態調用的方法名,怎樣才能不用傳入方法的參數類型就可以調用該方法呢?

     在已知類名的情況下,我們可以列印輸出該類的所有信息,當然包括類的成員方法;然後通過給定的方法名,對列印輸出的方法名進行篩選,找到我們需要的方法;再通過該方法的Method對象,得到該方法的參數類型、參數數量、和返回類型。那麼我們在外部動態調用該方法時,就不需要關心該類需要傳入的參數類型了,只需要傳入類名、方法名、參數值的信息即可。筆者實現了一個類LoadMethodEx,先從兩個類的同一個方法需要的參數方面做一個對比:

    Android反射機制實現與原理 - Nelson - Nelson

    Android反射機制實現與原理 - Nelson - Nelson

  1、LoadMethodEx類,少了一個參數(方法參數類型列表),本文直接從類LoadMethod內部獲取該參數類型列表,不需要用戶傳入該信息,好處其實也不言而喻了。

  2、方法的參數值:類LoadMethod是將所有的方法參數都做為一個String來傳入,在傳入再進行解析;而本文則直接使用Object類型做為參數類型,因為invoke(Object obj, Object...args)方法本身所需要的參數類型就是Object,避免了不必要的參數類型變換。

  在調用LoadMethodLoad()方法時,用戶只需要知道類名、方法名,並且將已經初始化的參數先向上轉型為Object,然後傳遞給Load()方法即可。方法的返回值為Object,這個肯定是由用戶根據自己的需要,再轉換成自己所需的類型。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第一: webpack只是構建 webpack-dev-server除了構建,還提供web服務 第二:webpack.config.json的路徑參數 顯然,entry都一樣,因為都要知道需要構建的文件在哪裡 那麼區別就在於 output了 path和webpack一起,指明構建 之後 輸出文件的位 ...
  • Express是基於Node.js平臺開發的Web應用開發框架,下麵我們入手學習。 官網 : http://www.expressjs.com.cn/ github:https://github.com/expressjs/express Express生成器 1、生成express全局指令npm ...
  • [1]視窗位置 [2]視窗大小 [3]打開視窗 [4]關閉視窗 ...
  • 在上面兩篇分別說明瞭設計中較為簡單也是很關鍵的實踐點。 第一模塊劃分,它是根據每個模塊所承載的業務,進行劃分,是應用程式一個靜態的描述。 第二合理組合,它是是將每個模塊調動起來,共同實現業務,是一個準動態的說明。 今天主要說明真個應用程式中消息和數據,以及如何迴圈,是完全動態的。同時也簡單的提到各種 ...
  • 1、界面上一個輸入框,一個按鈕,一個webview 。點按鈕,webview顯示輸入框中輸入的url的頁面。 @IBOutlet var wv:UIWebView = nil //定義一個UIWebView @IBOutlet var btnGo: UIView = nil //定義一個按鈕 @IB ...
  • AFNetworking的封裝 特點 1.將AFNetworking 3.0封裝.能夠很好享受蘋果開發中的面向對象開發思想 . 2.其中也提供幾種方法,來請求數據.包括:GET請求/POST請求/Upload請求. 3.調用的方法,在下麵詳細說明 使用方法 1.導入AFNetworking 文件夾 ...
  • 需求詳解: 在實際開發中,有可能是在後期優化的時候,會有這麼需要優化的需求:聊天輸入框保存之前輸入的文本,提高用戶的良好體驗。 在聊天模塊中,用戶可能會在輸入框輸入若幹字元,但是沒有點擊發送就點擊退出聊天,或者要點擊用戶頭像確認用戶的信息,或者比如需要向好友發送另一個好 友的ID不得不暫時退出當前好 ...
  • Swift - CALayer的contents屬性動畫 效果 源碼 https://github.com/YouXianMing/Swift-Animations ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...