多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Android中的自定義注解

Android中的自定義注解

來源:程序員人生   發布時間:2016-08-26 09:45:52 閱讀次數:3882次

轉載請標明出處:
http://blog.csdn.net/hai_qing_xu_kong/article/details/51779695
本文出自:【顧林海的博客】

前言

目前注解的使用頻率還是挺高,像第3方butterknife、數據庫ActiveAndroid等等,通過注解,我們的開發效力得到了明顯提高。因此理解注解并熟練使用注解是非常重要的,下面分為兩部份,第1部份是注解的介紹,資料來源于網上;第2部份是兩個小例子,利用注解+反射分別完成網絡要求的封裝和數據庫操作案例。

甚么是注解

注解是1種元數據, 可以添加到java代碼中. 類、方法、變量、參數、包都可以被注解,注解對注解的代碼沒有直接影響.

元注解

ava內置的注解有Override, Deprecated, SuppressWarnings等.
現在查看Override注解的源碼

@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }

發現Override注解上面有兩個注解, 這就是元注解. 元注解就是用來定義注解的注解.其作用就是定義注解的作用范圍, 使用在甚么元素上等等, 下面來詳細介紹.

元注解共有4種@Retention, @Target, @Inherited, @Documented

@Target:

   @Target說明了Annotation所修飾的對象范圍:Annotation可被用于 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
  作用:用于描寫注解的使用范圍(即:被描寫的注解可以用在甚么地方)
  取值(ElementType)有:
    1.CONSTRUCTOR:用于描寫構造器
    2.FIELD:用于描寫域
    3.LOCAL_VARIABLE:用于描寫局部變量
    4.METHOD:用于描寫方法
    5.PACKAGE:用于描寫包
    6.PARAMETER:用于描寫參數
    7.TYPE:用于描寫類、接口(包括注解類型) 或enum聲明

@Retention:

  @Retention定義了該Annotation被保存的時間長短:某些Annotation僅出現在源代碼中,而被編譯器拋棄;而另外一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機疏忽,而另外一些在class被裝載時將被讀?。ㄕ堊⒁馄鋵嵅挥绊慶lass的履行,由于Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命周期”限制。
  作用:表示需要在甚么級別保存該注釋信息,用于描寫注解的生命周期(即:被描寫的注解在甚么范圍內有效)
  取值(RetentionPoicy)有:
    1.SOURCE:在源文件中有效(即源文件保存)
    2.CLASS:在class文件中有效(即class保存)
    3.RUNTIME:在運行時有效(即運行時保存)

@Documented:

  @Documented用于描寫其它類型的annotation應當被作為被標注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是1個標記注解,沒有成員。

@Inherited:

  @Inherited 元注解是1個標記注解,@Inherited論述了某個被標注的類型是被繼承的。如果1個使用了@Inherited修飾的annotation類型被用于1個class,則這個annotation將被用于該class的子類。
  注意:@Inherited annotation類型是被標注過的class的子類所繼承。類其實不從它所實現的接口繼承annotation,方法其實不從它所重載的方法繼承annotation。
  當@Inherited annotation類型標注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這類繼承性。如果我們使用java.lang.reflect去查詢1個@Inherited annotation類型的annotation時,反射代碼檢查將展開工作:檢查class和其父類,直到發現指定的annotation類型被發現,或到達類繼承結構的頂層。

其中, @Retention是定義保存策略, 直接決定了我們用何種方式解析. SOUCE級別的注解是用來標記的, 比如Override, SuppressWarnings. 我們真正使用的類型是CLASS(編譯時)和RUNTIME(運行時)

自定義注解:

  使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節。在定義注解時,不能繼承其他的注解或接口。@interface用來聲明1個注解,其中的每個方法實際上是聲明了1個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)??梢酝ㄟ^default來聲明參數的默許值。
  
定義注解格式:

public @interface 注解名 {定義體}

注解參數的可支持數據類型:

  • 所有基本數據類型(int,float,boolean,byte,double,char,long,short)
  • String類型
  • Class類型
  • enum類型
  • Annotation類型
  • 以上所有類型的數組

栗子

栗子1:

在要求網絡數據時,會提供接口地址、要求數據等等1些參數,接下來展現的時如何利用反射和注解來封裝我們的要求部份:

package demo.src.demo.request.host; public enum Host { Host_1("https://L1"), Host_2("https://T2"), Host_3("https://R3"); private String host; Host(String host) { this.host = host; } public String getHost() { return host; } }

Host是我們的要求端口。

package demo.src.demo.request.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface RequestParamsKey { String key(); }
package demo.src.demo.request.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import demo.src.demo.request.host.Host; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface RequestParamsUrl { //接口地址 String url(); //端口 Host host() default Host.Host_1; //緩存 boolean isCache() default false; }

RequestParamsKey 注解用于要求的鍵值對,RequestParamsUrl 注解用于要求的地址、端口和1些配置參數。

package demo.src.demo.request; import java.lang.reflect.Field; import demo.src.demo.request.params.RequestParamsKey; import demo.src.demo.request.params.RequestParamsUrl; /** * 拼接要求參數 * * @author glh * */ public class RequestParam { private RequestParam() { } /** * 獲得request參數 * @param _clazz * @param _object * @return */ public static String getParam(Class<?> _clazz, Object _object) { Class<?> clazz = _clazz; Field[] fields = clazz.getDeclaredFields(); try { return requestParam(fields, clazz, _object); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * 獲得要求路徑 * * @param fields * @param clazz * @param _object * @return * @throws IllegalAccessException * @throws IllegalArgumentException */ private static String requestParam(Field[] fields, Class<?> clazz, Object _object) throws IllegalArgumentException, IllegalAccessException { StringBuilder request = new StringBuilder(); RequestParamsUrl requestParamsUrl = (RequestParamsUrl) clazz.getAnnotation(RequestParamsUrl.class); if (requestParamsUrl != null) { String url = requestParamsUrl.url(); boolean isCache = requestParamsUrl.isCache(); String host = requestParamsUrl.host().getHost(); request.append(host); request.append(url); request.append("?"); System.out.println("要求端口:" + host); System.out.println("要求地址:" + url); System.out.println("是不是緩存:" + isCache); } for (Field field : fields) { RequestParamsKey requestParamsKey = field.getAnnotation(RequestParamsKey.class); if (requestParamsKey != null) { String key = requestParamsKey.key(); String Value = (String) field.get(_object); request.append(key); request.append("="); request.append(Value); request.append("&"); } } request.deleteCharAt(request.length() - 1); System.out.println("要求路徑:" + request.toString()); return request.toString(); } }

RequestParam 類用于解析我們自定義的注解并獲得所需的參數。

接下來看如何定義我們的要求參數request:

package demo.src.demo.reqBody; import demo.src.demo.request.host.Host; import demo.src.demo.request.params.RequestParamsKey; import demo.src.demo.request.params.RequestParamsUrl; @RequestParamsUrl(url = "getLocation.php", isCache = true, host = Host.Host_2) public class LocationReq { @RequestParamsKey(key = "lat_key") public String lat; @RequestParamsKey(key = "lan_key") public String lan; }
package demo.src.demo; import demo.src.demo.reqBody.LocationReq; import demo.src.demo.request.RequestParam; public class demo { public LocationReq mLocation; public static void main(String[] args) throws ClassNotFoundException { demo demo = new demo(); demo.cofig(); demo.getRequest(); } /** * 設置要求參數 */ private void cofig() { mLocation = new LocationReq(); mLocation.lan = "123.09"; mLocation.lat = "232.34"; } /** * 獲得要求路徑 */ private void getRequest(){ System.out.println(RequestParam.getParam(mLocation.getClass(),mLocation)); } }

輸出結果:

要求端口:https://T2
要求地址:getLocation.php
是不是緩存:true
要求路徑:https://T2getLocation.php?lat_key=232.34&lan_key=123.09
https://T2getLocation.php?lat_key=232.34&lan_key=123.09

栗子2:

下面是通過注解和反射定義數據庫的創建等操作:

package com.example.dbannotion.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; /** * 數據庫 * @author glh * */ public class SqliteHelper extends SQLiteOpenHelper{ private String createTable; private String tableName; public SqliteHelper(Context context, String name, CursorFactory factory, int version,String createTable,String tableName) { super(context, name, factory, version); this.createTable=createTable; this.tableName=tableName; } /** * 創建表 */ @Override public void onCreate(SQLiteDatabase db) { if(createTable!=""){ db.execSQL(createTable); } } /** * 更新表 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL( "DROP TABLE IF EXISTS " + tableName ); onCreate(db); } /** * 更新列 * @param db * @param oldColumn * @param newColumn * @param typeColumn */ public void updateColumn(SQLiteDatabase db, String oldColumn, String newColumn, String typeColumn){ try{ db.execSQL( "ALTER TABLE " + tableName + " CHANGE " + oldColumn + " "+ newColumn + " " + typeColumn ); } catch(Exception e){ e.printStackTrace(); } } }

SqliteHelper 用于創建、更新數據庫操作。

package com.example.dbannotion.db.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ColumDB { String column(); }
package com.example.dbannotion.db.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface TableDB { String table();//表名 String dbName() default "demoDb.db";//數據庫名稱 int version() default 1;//版本號 }

ColumDB 注解用于列數據(鍵值對),TableDB 注解用于表和數據庫的配置參數。

package com.example.dbannotion.db; import java.lang.reflect.Field; import java.util.ArrayList; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import com.example.dbannotion.db.annotation.ColumDB; import com.example.dbannotion.db.annotation.TableDB; public abstract class AbstractDB { public static final String TAG = "AbstractDB"; private SQLiteDatabase db; private SqliteHelper dbHelper; // 版本 private int version; // 數據庫名稱 private String dbName; // 表名 private String tableName; // 建表語句 private StringBuilder createBuilder; // 插入的數據 private ContentValues contentValues = new ContentValues(); // 是不是存在數據 private boolean isColums; private ArrayList<String> clumsList = new ArrayList<String>(); /** * 打開數據庫 * * @param _context * @param _clazz * @param _object * @return */ public AbstractDB open(Context _context, Class<?> _clazz, Object _object) { if (paramsDB(_clazz, _object)) { dbHelper = new SqliteHelper(_context, dbName, null, version, createBuilder.toString(), tableName); db = dbHelper.getWritableDatabase(); Log.e(TAG, "-------------數據庫打開成功!----------"); } else { Log.e(TAG, "-------------數據庫打開失?。?---------"); } return this; } /** * 打開數據庫時是不是進行插入操作 * * @param isInsert * @return */ public AbstractDB isInsert(boolean isInsert) { if (isInsert && isColums) { insert(); } return this; } /** * 創建并檢查數據庫 * * @param _object * @param _clazz * @return false:失敗 true:成功 */ public boolean paramsDB(Class<?> _clazz, Object _object) { isColums = false; contentValues.clear(); clumsList.clear(); createBuilder = new StringBuilder(); Class<?> clazz = _clazz; Field[] fields = clazz.getDeclaredFields(); createBuilder.append("CREATE TABLE IF NOT EXISTS "); /* * 表名 */ TableDB tDb = _clazz.getAnnotation(TableDB.class); if (tDb != null) { dbName = tDb.dbName(); tableName = tDb.table(); version = tDb.version(); createBuilder.append(tableName); createBuilder.append("("); } else { return false; } /* * 列 */ for (Field field : fields) { ColumDB requestParamsKey = field.getAnnotation(ColumDB.class); if (requestParamsKey != null) { String key = requestParamsKey.column(); String value; try { value = (String) field.get(_object); clumsList.add(key); if (!value.isEmpty()) { contentValues.put(key, value); } createBuilder.append(key); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } createBuilder.append(" varchar,"); isColums = true; } } if (!isColums) { return false; } createBuilder.deleteCharAt(createBuilder.length() - 1); createBuilder.append(")"); return true; } public AbstractDB insert() { if (contentValues != null) { db.insert(tableName, null, contentValues); Log.e(TAG, "-------------數據添加成功!----------"); } else { Log.e(TAG, "-------------數據添加失??!----------"); } return this; } /** * 獲得數據 * * @return */ public String getDate() { StringBuilder dateBuilder = new StringBuilder(); SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from " + tableName, null); while (cursor.moveToNext()) { if (clumsList != null) { for (int i = 0, length = clumsList.size(); i < length; i++) { String name = cursor.getString(cursor.getColumnIndex(clumsList.get(i))); dateBuilder.append(clumsList.get(i)); dateBuilder.append("="); dateBuilder.append(name); dateBuilder.append(","); } dateBuilder.append("\n"); } } cursor.close(); if (dateBuilder.length() > 1) { dateBuilder.deleteCharAt(dateBuilder.length() - 1); return dateBuilder.toString(); } else { Log.e(TAG, "-------------無數據解析!----------"); return ""; } } public void Close() { db.close(); dbHelper.close(); } }

AbstractDB 是1個抽象類,用于數據庫的操作。

以下是建表操作:

package com.example.dbannotion.table; import com.example.dbannotion.db.AbstractDB; import com.example.dbannotion.db.annotation.ColumDB; import com.example.dbannotion.db.annotation.TableDB; @TableDB(table = "student",dbName="demo.db",version=1) public class Student extends AbstractDB { @ColumDB(column = "name") public String name; @ColumDB(column = "age") public String age; @ColumDB(column = "sex") public String sex; }

創建了1個demo.db數據庫,表面為student,版本號1,name,age,sex列。

package com.example.dbannotion; import com.example.dbannotion.table.Student; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private Student student; public TextView tv_show; public Button btn_get; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initDate(); initView(); initEvent(); } private void initView() { tv_show = (TextView) findViewById(R.id.tv_show); btn_get = (Button) findViewById(R.id.btn_get); } private void initEvent() { btn_get.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { new Handler().post(new Runnable() { @Override public void run() { tv_show.setText(student.getDate()); } }); } }); } private void initDate() { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { student = new Student(); student.age = i + ""; student.name = "name-" + i; if (i % 2 == 0) { student.sex = "男"; } else { student.sex = "女"; } student.open(MainActivity.this, student.getClass(), student).isInsert(true); } } }).start(); } }

運行結果:

這里寫圖片描述

以上栗子只是起了1個拋磚迎玉的作用,大家可以定義出合適當前業務場景注解框架。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产精品2 | 性xxxx黑人与亚洲 | 欧美精品福利 | 免费视频网站在线观看 | 欧美xxx69╳xxhd | 自拍偷拍第一页 | 一国产一级淫片a免费播放口 | 国产综合亚洲欧美日韩一区二区 | 亚洲国产成人精品不卡青青草原 | 国产亚洲精品中文带字幕21页 | 欧美性色欧美a在线播放 | 久久久久久国产精品视频 | 欧美日韩国产高清一区二区三区 | 福利片在线观看 | 99伊人网| 国产精品久久久免费视频 | 视频免费在线观看 | 国产片免费看 | 精久久 | 国产在线精品福利一区二区三区 | 久久精品视频免费 | 亚洲毛片免费视频 | 污污成人一区二区三区四区 | 亚洲一区二区精品视频 | 色婷婷影院在线视频免费播放 | 免费播放成人生活片 | 国产高清一 | 欧美亚洲国产一区二区三区 | 小说区图片区亚洲 | 国产免费一区2区3区4区 | 久久综合精品国产一区二区三区无 | 欧美 日韩 国产在线 | 中文字幕日本一本二本三区 | 欧美美女xx | 午夜dj视频在线观看免费 | 欧美日韩一本二本 | 在线中文字幕精品第5页 | 日本专区 | 麻豆国产免费看片在线播放 | 狍和美女一级aa毛片 | 99久久999久久久综合精品涩 |