该系统有两个应用,比较繁琐。但是内容提供者是android里非常非常重要的一个内容,我们得好好学习下哦。先看效果图,我们提供了四个按钮,点击按钮便会进行相应的操作。

我们先看内容提供者所在的应用,代码结构:

activity代码:

  1. package cn.com.contentProvider;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;
  5. public class ContentProviderAcitivity extends Activity {
  6. @Override
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.main);
  10. }
  11. }

MyContentProvider.java代码

  1. package cn.com.contentProvider;
  2. import android.content.ContentProvider;
  3. import android.content.ContentUris;
  4. import android.content.ContentValues;
  5. import android.content.Context;
  6. import android.content.UriMatcher;
  7. import android.database.Cursor;
  8. import android.database.sqlite.SQLiteDatabase;
  9. import android.database.sqlite.SQLiteOpenHelper;
  10. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  11. import android.net.Uri;
  12. /**
  13. *
  14. * @author chenzheng_java
  15. * @description 自定义的内容提供者.
  16. *  总结下访问内容提供者的主要步骤:
  17. * 第一:我们要有一个uri,这就相当于我们的网址,我们有了网址才能去访问具体的网站
  18. * 第二:我们去系统中寻找该uri中的authority(可以理解为主机地址),
  19. *      只要我们的内容提供者在manifest.xml文件中注册了,那么系统中就一定存在。
  20. * 第三:通过内容提供者内部的uriMatcher对请求进行验证(你找到我了,还不行,我还得看看你有没有权限访问我呢)。
  21. * 第四:验证通过后,就可以调用内容提供者的增删查改方法进行操作了
  22. */
  23. public class MyContentProvider extends ContentProvider {
  24. // 自己实现的数据库操作帮助类
  25. private MyOpenHelper myOpenHelper;
  26. // 数据库相关类
  27. private SQLiteDatabase sqLiteDatabase;
  28. // uri匹配相关
  29. private static UriMatcher uriMatcher;
  30. // 主机名称(这一部分是可以随便取得)
  31. private static final String authority = "cn.com.chenzheng_java.hello";
  32. // 注册该内容提供者匹配的uri
  33. static {
  34. uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  35. /*
  36. * path_chenzheng部分的字符串是随便取得,1代表着如果请求的uri与当前加入
  37. * 的匹配uri正好吻合,uriMathcher.match()方法返回的值.#代表任意数字,*代表任意字符串
  38. */
  39. uriMatcher.addURI(authority, "path_chenzheng", 1);// 代表当前表中的所有的记录
  40. uriMatcher.addURI(authority, "path_chenzheng/#", 2);// 代表当前表中的某条特定的记录,记录id便是#处得数字
  41. }
  42. // 数据表中的列名映射
  43. private static final String _id = "id";
  44. private static final String name = "name";
  45. private static final String age = "age";
  46. private static final String isMan = "isMan";
  47. /**
  48. * @description 当内容提供者第一次创建时执行
  49. */
  50. @Override
  51. public boolean onCreate() {
  52. try {
  53. myOpenHelper = new MyOpenHelper(getContext(), DB_Name, null,
  54. Version_1);
  55. } catch (Exception e) {
  56. return false;
  57. }
  58. return true;
  59. }
  60. /**
  61. * @description 对数据库进行删除操作的时候执行
  62. *              android.content.ContentUri为我们解析uri相关的内容提供了快捷方便的途径
  63. */
  64. @Override
  65. public int delete(Uri uri, String selection, String[] selectionArgs) {
  66. int number = 0;
  67. sqLiteDatabase = myOpenHelper.getWritableDatabase();
  68. int code = uriMatcher.match(uri);
  69. switch (code) {
  70. case 1:
  71. number = sqLiteDatabase
  72. .delete(Table_Name, selection, selectionArgs);
  73. break;
  74. case 2:
  75. long id = ContentUris.parseId(uri);
  76. /*
  77. * 拼接where子句用三目运算符是不是特烦人啊? 实际上,我们这里可以用些技巧的.
  78. * if(selection==null||"".equals(selection.trim())) selection =
  79. * " 1=1 and "; selection+=_id+"="+id;
  80. * 拼接where子句中最麻烦的就是and的问题,这里我们通过添加一个1=1这样的恒等式便将问题解决了
  81. */
  82. selection = (selection == null || "".equals(selection.trim())) ? _id
  83. + "=" + id
  84. : selection + " and " + _id + "=" + id;
  85. number = sqLiteDatabase
  86. .delete(Table_Name, selection, selectionArgs);
  87. break;
  88. default:
  89. throw new IllegalArgumentException("异常参数");
  90. }
  91. return number;
  92. }
  93. /**
  94. *@description 获取当前内容提供者的MIME类型 集合类型必须添加前缀vnd.android.cursor.dir/(该部分随意)
  95. *              单条记录类型添加前缀vnd,android.cursor.item/(该部分随意)
  96. *              定义了该方法之后,系统会在第一次请求时进行验证,验证通过则执行crub方法时不再重复进行验证,
  97. *              否则如果没有定义该方法或者验证失败,crub方法执行的时候系统会默认的为其添加类型验证代码。
  98. */
  99. @Override
  100. public String getType(Uri uri) {
  101. int code = uriMatcher.match(uri);
  102. switch (code) {
  103. case 1:
  104. return "vnd.android.cursor.dir/chenzheng_java";
  105. case 2:
  106. return "vnd.android.cursor.item/chenzheng_java";
  107. default:
  108. throw new IllegalArgumentException("异常参数");
  109. }
  110. }
  111. /**
  112. * @description 对数据表进行insert时执行该方法
  113. */
  114. @Override
  115. public Uri insert(Uri uri, ContentValues values) {
  116. sqLiteDatabase = myOpenHelper.getWritableDatabase();
  117. int code = uriMatcher.match(uri);
  118. switch (code) {
  119. case 1:
  120. sqLiteDatabase.insert(Table_Name, name, values);
  121. break;
  122. case 2:
  123. long id = sqLiteDatabase.insert(Table_Name, name, values);
  124. // withAppendId将id添加到uri的最后
  125. ContentUris.withAppendedId(uri, id);
  126. break;
  127. default:
  128. throw new IllegalArgumentException("异常参数");
  129. }
  130. return uri;
  131. }
  132. /**
  133. * 当执行查询时调用该方法
  134. */
  135. @Override
  136. public Cursor query(Uri uri, String[] projection, String selection,
  137. String[] selectionArgs, String sortOrder) {
  138. Cursor cursor = null;
  139. sqLiteDatabase = myOpenHelper.getReadableDatabase();
  140. int code = uriMatcher.match(uri);
  141. switch (code) {
  142. case 1:
  143. cursor = sqLiteDatabase.query(Table_Name, projection, selection,
  144. selectionArgs, null, null, sortOrder);
  145. break;
  146. case 2:
  147. // 从uri中解析出ID
  148. long id = ContentUris.parseId(uri);
  149. selection = (selection == null || "".equals(selection.trim())) ? _id
  150. + "=" + id
  151. : selection + " and " + _id + "=" + id;
  152. cursor = sqLiteDatabase.query(Table_Name, projection, selection,
  153. selectionArgs, null, null, sortOrder);
  154. break;
  155. default:
  156. throw new IllegalArgumentException("参数错误");
  157. }
  158. return cursor;
  159. }
  160. /**
  161. * 当执行更新操作的时候执行该方法
  162. */
  163. @Override
  164. public int update(Uri uri, ContentValues values, String selection,
  165. String[] selectionArgs) {
  166. int num = 0;
  167. sqLiteDatabase = myOpenHelper.getWritableDatabase();
  168. int code = uriMatcher.match(uri);
  169. switch (code) {
  170. case 1:
  171. num = sqLiteDatabase.update(Table_Name, values, selection, selectionArgs);
  172. break;
  173. case 2:
  174. long id = ContentUris.parseId(uri);
  175. selection = (selection == null || "".equals(selection.trim())) ? _id
  176. + "=" + id
  177. : selection + " and " + _id + "=" + id;
  178. num = sqLiteDatabase.update(Table_Name, values, selection, selectionArgs);
  179. break;
  180. default:
  181. break;
  182. }
  183. return num;
  184. }
  185. // 数据库名称
  186. private final String DB_Name = "chenzheng_java.db";
  187. // 数据表名
  188. private final String Table_Name = "chenzheng_java";
  189. // 版本号
  190. private final int Version_1 = 1;
  191. private class MyOpenHelper extends SQLiteOpenHelper {
  192. public MyOpenHelper(Context context, String name,
  193. CursorFactory factory, int version) {
  194. super(context, name, factory, version);
  195. }
  196. /**
  197. * @description 当数据表无连接时创建新的表
  198. */
  199. @Override
  200. public void onCreate(SQLiteDatabase db) {
  201. String sql = " create table if not exists " + Table_Name
  202. + "(id INTEGER,name varchar(20),age integer,isMan boolean)";
  203. db.execSQL(sql);
  204. }
  205. /**
  206. * @description 当版本更新时触发的方法
  207. */
  208. @Override
  209. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  210. String sql = " drop table if exists " + Table_Name;
  211. db.execSQL(sql);
  212. onCreate(db);
  213. }
  214. }
  215. }

androidManifest.xml代码

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="cn.com.contentProvider" android:versionCode="1"
  4. android:versionName="1.0">
  5. <uses-sdk android:minSdkVersion="8" />
  6. <application android:icon="@drawable/icon" android:label="@string/app_name">
  7. <activity android:name=".ContentProviderAcitivity"
  8. android:label="@string/app_name">
  9. <intent-filter>
  10. <action android:name="android.intent.action.MAIN" />
  11. <category android:name="android.intent.category.LAUNCHER" />
  12. </intent-filter>
  13. </activity>
  14. <provider android:name=".MyContentProvider"
  15. android:authorities="cn.com.chenzheng_java.hello"
  16. android:multiprocess="true" android:permission="cn.com.chenzheng_java.permission"></provider>
  17. </application>
  18. <!--
  19. permission中的android:name的值与provider中的android:permission的值是一样的
  20. android:protectionLevel 则代表了权限等级
  21. -->
  22. <permission android:name="cn.com.chenzheng_java.permission"
  23. android:protectionLevel="normal"></permission>
  24. </manifest>

main.xml为默认。

----------------------------------------------------------------------------------------------------------------

第二个应用(用于访问内容提供者的应用)

activity代码

  1. package cn.com.chenzheng_java;
  2. import android.app.Activity;
  3. import android.content.ContentResolver;
  4. import android.content.ContentValues;
  5. import android.database.Cursor;
  6. import android.net.Uri;
  7. import android.os.Bundle;
  8. import android.util.Log;
  9. import android.view.View;
  10. import android.widget.Button;
  11. import android.widget.TextView;
  12. /**
  13. *
  14. * @author chenzheng_java
  15. * @description 通过访问内容提供者进行增删查改.注意本程序中为了方便阅读,
  16. * 在需要数据库列名的地方直接写上了数据库中字段的名称,实际上这是不合理的,
  17. * 作为内容提供者的使用者,我们不可能在使用这个内容提供者之前先去了解sqlite
  18. * 中表的结构。比较适宜的做法是,在内容提供者中将愿意提供给外部访问的字段名称(列名)
  19. * 定义为string final 的常量!
  20. */
  21. public class ContentAccessActivity extends Activity {
  22. private final static String tag = "通知";
  23. private TextView textView;
  24. String result = "结果:/n";
  25. ContentResolver reslover;
  26. Uri uri;
  27. @Override
  28. public void onCreate(Bundle savedInstanceState) {
  29. super.onCreate(savedInstanceState);
  30. setContentView(R.layout.main);
  31. /**
  32. * 这里我们一定要搞清楚,uri的内容到底和内容提供者中哪个地方一一对应
  33. * 在MyContentProvider中我们有如下片段
  34. * uriMatcher.addURI(authority, "path_chenzheng", 1);// 代表当前表中的所有的记录
  35. uriMatcher.addURI(authority, "path_chenzheng/#", 2);// 代表当前表中的某条特定的记录,记录id便是#处得数字
  36. 其中authority为cn.com.chenzheng_java.hello。
  37. */
  38. uri = Uri.parse("content://cn.com.chenzheng_java.hello/path_chenzheng");
  39. /**
  40. * 内容提供者是什么?内容提供者相当于一个封装好了增删改查操作的接口,这个接口有一把锁,只有携带钥匙的访问者才能访问。
  41. * ContentResolver是什么?ContentResolver是一个开锁匠,他携带者钥匙(钥匙上有标签显示他是那个门得钥匙,如path_chenzheng)
  42. * 去寻找内容提供者,然后访问内容提供者的增删查改方法
  43. * 我们这里调用contentResolver的增删查改就相当于将任务交给了锁匠,
  44. * 然后让锁匠去找能打开的内容提供者,并且执行里面相应的方法,并将结果返回.
  45. * ContentResolver的好处在于,我们可以无视CotentProvider的具体实现,无论contentProvider里面是如何实现的,我想执行
  46. * 某一个操作时,所要书写的代码都是一样的。
  47. */
  48. reslover = this.getContentResolver();
  49. textView = (TextView) findViewById(R.id.textView);
  50. Button insertButton = (Button) findViewById(R.id.insertButton);
  51. insertButton.setOnClickListener(new View.OnClickListener() {
  52. @Override
  53. public void onClick(View v) {
  54. insert(reslover, uri);
  55. }
  56. });
  57. Button deleteButton = (Button) findViewById(R.id.deleteButton);
  58. deleteButton.setOnClickListener(new View.OnClickListener() {
  59. @Override
  60. public void onClick(View v) {
  61. delete(reslover, uri);
  62. }
  63. });
  64. Button updateButton = (Button) findViewById(R.id.updateButton);
  65. updateButton.setOnClickListener(new View.OnClickListener() {
  66. @Override
  67. public void onClick(View v) {
  68. update(reslover, uri);
  69. }
  70. });
  71. Button queryButton = (Button) findViewById(R.id.queryButton);
  72. queryButton.setOnClickListener(new View.OnClickListener() {
  73. @Override
  74. public void onClick(View v) {
  75. query(reslover, uri);
  76. }
  77. });
  78. }
  79. private void insert(ContentResolver resolver, Uri uri) {
  80. ContentValues contentValues = new ContentValues();
  81. contentValues.put("name", "张小凡");
  82. contentValues.put("age", 22);
  83. contentValues.put("isMan", true);
  84. Uri uri2 = resolver.insert(uri, contentValues);
  85. Log.i(tag, "插入成功!");
  86. result += "成功插入了一条记录,uri为" + uri2;
  87. textView.setText(result);
  88. result = "";
  89. }
  90. private void update(ContentResolver resolver, Uri uri) {
  91. ContentValues contentValues = new ContentValues();
  92. contentValues.put("age", 122);
  93. int number = resolver.update(uri, contentValues, null, null);
  94. Log.i(tag, "更新成功!");
  95. result += "成功更新了" + number+"条记录";
  96. textView.setText(result);
  97. result = "";
  98. }
  99. private void delete(ContentResolver resolver, Uri uri) {
  100. String where = " 1=1 and isMan=?";
  101. //这里要注意哦,sqlite数据库中是没有boolean的,true会被转成1存储
  102. String[] selectionArgs = new String[] { "1" };
  103. int number = resolver.delete(uri, where, selectionArgs);
  104. Log.i(tag, "删除成功!");
  105. textView.setText(result + "成功删除了" + number + "条记录");
  106. result = "";
  107. }
  108. private void query(ContentResolver resolver, Uri uri) {
  109. String[] projection = new String[] { "id", "name", "age", "isMan" };
  110. Cursor cursor = resolver.query(uri, projection, null, null, null);
  111. int count = cursor.getCount();
  112. Log.i(tag, "总记录数" + count);
  113. int idIndex = cursor.getColumnIndex("id");
  114. int nameIndex = cursor.getColumnIndex("name");
  115. int ageIndex = cursor.getColumnIndex("age");
  116. int isManIndex = cursor.getColumnIndex("isMan");
  117. cursor.moveToFirst();
  118. while (!cursor.isAfterLast()) {
  119. int id = cursor.getInt(idIndex);
  120. String name = cursor.getString(nameIndex);
  121. int age = cursor.getInt(ageIndex);
  122. int isMan = cursor.getInt(isManIndex);
  123. Log.i(tag, "id=" + id + " name=" + name + " age=" + age + " isMan="
  124. + isMan);
  125. result += "id=" + id + " name=" + name + " age=" + age + " isMan="
  126. + isMan;
  127. cursor.moveToNext();
  128. }
  129. textView.setText(result);
  130. result = "";
  131. }
  132. }

manifest.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="cn.com.chenzheng_java"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <uses-sdk android:minSdkVersion="8" />
  7. <application android:icon="@drawable/icon" android:label="@string/app_name">
  8. <activity android:name=".ContentAccessActivity"
  9. android:label="@string/app_name">
  10. <intent-filter>
  11. <action android:name="android.intent.action.MAIN" />
  12. <category android:name="android.intent.category.LAUNCHER" />
  13. </intent-filter>
  14. </activity>
  15. </application>
  16. <!-- 添加对内容提供者访问的权限,该权限是有我们自己定义的哦 -->
  17. <uses-permission android:name="cn.com.chenzheng_java.permission"></uses-permission>
  18. </manifest>

main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView
  8. android:id="@+id/textView"
  9. android:layout_width="fill_parent"
  10. android:layout_height="wrap_content"
  11. android:text="@string/hello"
  12. />
  13. <Button
  14. android:id="@+id/insertButton"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:text="insert"
  18. ></Button>
  19. <Button
  20. android:id="@+id/deleteButton"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:text="delete"
  24. ></Button>
  25. <Button
  26. android:id="@+id/updateButton"
  27. android:layout_width="wrap_content"
  28. android:layout_height="wrap_content"
  29. android:text="update"
  30. ></Button>
  31. <Button
  32. android:id="@+id/queryButton"
  33. android:layout_width="wrap_content"
  34. android:layout_height="wrap_content"
  35. android:text="query"
  36. ></Button>
  37. </LinearLayout>

--------------------------------------------------------------------------------

想说的话,在代码的注释中已经说的很清晰了。这里再次重复下我们定义和使用内容提供者的步骤吧。

定义内容提供者:

我们定义内容提供者的目的是什么,共享数据,对,定义内容提供者的目的就是让别的应用能够访问当前应用的一些数据,至于到底暴露给外界什么数据,我们可以 在定义内容提供者的时候详细控制!不管如何,我们明确了第一个问题,定义内容提供者的目的----数据共享!

我们平时对数据的操作都有哪些?增删改查!就四个字!这也是为什么我们再定义内容提供者的时候必须要实现相应的方法了。当然如果你要是不想提供相应的操作,你可以在内部进行方法空实现。

是不是所有的应用都可以访问我啊?不可能!我们可不是随便的人,对吧!所以我们要进行验证,验证不通过的直接让它去死就可以了。验证怎么验证啊?通过UriMatcher进行匹配!

现在我们已经提供了访问接口了,我们怎么让系统知道,别的应用可以用我的东西啊?去配置文件中注册!!

使用内容提供者:

如何找到该内容提供者啊?需要Uri和相应的访问权限。相当于地址

如何进行增删查改啊?通过ContentResolver对象的相应方法。

android之内容提供者解析的更多相关文章

  1. Android 中内容提供者的使用

    在Android中内容提供者主要是用于不同程序之间的数据共享.内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序的数据,另一种是创建自己的内容提供器,供其他的程序访问. 使用现 ...

  2. Android 之内容提供者 内容解析者 内容观察者

    contentProvider:ContentProvider在Android中的作用是对外提供数据,除了可以为所在应用提供数据外,还可以共享数据给其他应用,这是Android中解决应用之间数据共享的 ...

  3. [Android Pro] 内容提供者ContentProvider的基本使用

    一.ContentProvider简介 当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.ContentProvider为存储和获取数据提 ...

  4. Android中内容提供者ContentProvider的详解

    1.什么是ContentProvider 首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少. ContentProvider为不 ...

  5. Android使用内容提供者实现增删改查操作

    Android使用内容提供者实现增删改查操作 这里需要建立两个项目:SiYouShuJuKu(使用内容提供者暴露相关的操作),DQDYGApplication(使用内容解析者对第一个应用进行相关的解析 ...

  6. Android -- ContentProvider 内容提供者,创建和调用

    1. 概述 ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentPr ...

  7. Android基础内容提供者ContentProvider的使用详解(转)

    1.什么是ContentProvider 首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少. ContentProvider为不 ...

  8. android contentprovider内容提供者

    contentprovider内容提供者:让其他app可以访问私有数据库(文件) 1.AndroidManifest.xml 配置provider <?xml version="1.0 ...

  9. Android之内容提供者ContentProvider的总结

    本文包含以下知识点: ContentProvider Uri 的介绍 ContentResolver: 监听ContentProvider的数据改变 一:ContentProvider部分 Conte ...

随机推荐

  1. 20162327实验一Java开发环境的熟悉实验报告

    20162327 <程序设计与数据结构>第一次实验报告 基础知识 1.JDB的使用 使用JDB调试程序需要以下五个步骤: 1.设置断点 stop in 2.run 3.print 4.ne ...

  2. [Winform]线程间操作无效,从不是创建控件的线程访问它的几个解决方案,async和await?

    目录 概述 取消跨线程检查 使用委托异步调用 sync和await 总结 概述 最近在qq群里有一朋友,问起在winform中怎么通过开启线程的方式去处理耗时的操作,比如,查看某个目录下所有的文件,或 ...

  3. bash中的通配符使用

    通配符的使用 bash命令中的字符由:普通字符.通配符.元字符.转义符构成. 通配符 由shell处理的(不是由所涉及到命令语句处理的,其实我们在shell各个命令中也没有发现有这些通配符介绍), 它 ...

  4. MySql_安装及简单命令

    一.下载MySql http://dev.mysql.com/downloads/file/?id=461390 版本位5.7.11.0.msi,32位的,但是该版本在64位机器上也可以使用 二.安装 ...

  5. Qunit的使用

    1.新建一个html页面,如下 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "ht ...

  6. c#中的数组、ArrayList、List区别

    首先说明C#中的Array类:Array 类是 C# 中所有数组的基类,它是在 System 命名空间中定义.Array 类提供了各种用于数组的属性和方法.关于Array类的一些属性及方法详见博文:C ...

  7. Vue-router路由基础总结(一)

    一.安装 npm下载:npm install vue-router 如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装路由功能:在你的文件夹下的 src 文件夹下的 main.j ...

  8. 破解IDEA Ultimate2017 测试

    转载:http://blog.csdn.net/linyanqing21/article/details/72594352 IntelliJ Idea 2017 免费激活方法: 1.到网站 http: ...

  9. Android adb shell学习心得(四)

    1.awk中的sub sub为替换函数.形式如 sub(/1/,"",$2) 将第二个变量的第一个1替换为空,若将sub替换为gsub.则替换全部的1. 2.awk中的-F 分隔符 ...

  10. 常用HTML标签的全称及描述

    常用HTML标签的英文全称及简单描述   HTML标签 英文全称 中文释义 a Anchor 锚 abbr Abbreviation 缩写词 acronym Acronym 取首字母的缩写词 addr ...