热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android之单元测试——下

在本文中,就我在HYB项目中实际遇到的问题,和大家做一个分享.#1.在控件的模拟事件执行的时候,尽量不要使用UiThreadTest.因为如果一个Activity中,控件很多的话,

在本文中,就我在HYB项目中实际遇到的问题,和大家做一个分享.

#1.在控件的模拟事件执行的时候,尽量不要使用@UiThreadTest.因为如果一个Activity中,控件很多的话,很容易造成UI线程阻塞.

可以采用如下一段代码代替之:

1 private class PerformClick implements Runnable {
2 Button hhButton;
3 public PerformClick(Button HHButton) {
4 hhButton = HHButton;
5 }
6
7 @Override
8 public void run() {
9 hhButton.performClick();
10 }
11 }

#2.怎样对控件进行压力测试,我的处理是不停的调用View的Click事件

1 public void stressTestForButton(final Button btn,int pressNumber) {
2 for(int i &#61; 0;i <&#61; pressNumber;i&#43;&#43;) {
3 new Thread(new Runnable() {
4 &#64;Override
5 public void run() {
6 btn.requestFocus();
7 btn.performClick();
8 btn.clearFocus();
9 }
10 });
11 Log.i("count times", i &#43; "");
12 }
13 }

#3.对控件上显示字段的测试,显示的字段来自strings.xml

1 public void testText() {
2 //testing String values
3 assertEquals(hayhouseLinkButtonString, (String)hayhouseLinkButton.getText());
4 assertEquals(hayhouseradioLinkButtonString, (String)hayhouseradioLinkButton.getText());
5 assertEquals(healLinkButtonString, (String)healLinkButton.getText());
6 }

#4.怎样在Activity中对各个Button的压力测试,注意对线程的控制

1 public void testButtonStress() {
2 Log.v(TAG, "testButtonStress method is starting");
3 SystemClock.sleep(400);
4 new OperateUtil().new performButtonClickStress(hayhouseLinkButton,10);
5 SystemClock.sleep(400);
6 addClickTimes(hayhouseLinkButton,50);
7 SystemClock.sleep(400);
8 addClickTimes(hayhouseLinkButton,100);
9 SystemClock.sleep(400);
10 addClickTimes(hayhouseLinkButton,200);
11 SystemClock.sleep(400);
12 new OperateUtil().new performButtonClickStress(hayhouseradioLinkButton,10);
13 SystemClock.sleep(400);
14 addClickTimes(hayhouseradioLinkButton,50);
15 SystemClock.sleep(400);
16 addClickTimes(hayhouseradioLinkButton,100);
17 SystemClock.sleep(400);
18 addClickTimes(hayhouseradioLinkButton,200);
19 SystemClock.sleep(400);
20 new OperateUtil().new performButtonClickStress(healLinkButton,10);
21 SystemClock.sleep(400);
22 addClickTimes(healLinkButton,50);
23 SystemClock.sleep(400);
24 addClickTimes(healLinkButton,100);
25 SystemClock.sleep(400);
26 addClickTimes(healLinkButton,200);
27 }

#5.在tearDown()方法里面一般进行的操作

1 &#64;Override
2 protected void tearDown() throws Exception {
3 hayhouseLinkButton.clearFocus();
4 hayhouseLinkButton.clearComposingText();
5 hayhouseradioLinkButton.clearFocus();
6 hayhouseradioLinkButton.clearComposingText();
7 healLinkButton.clearFocus();
8 healLinkButton.clearComposingText();
9 detailView.clearFocus();
10
11 hayHouseActivity.finish();
12 super.tearDown();
13 }

#6.在app跑起来前,要保证所有的widget不能为空.

public void testPreConditions() {assertTrue(hayhouseLinkButton !&#61; null);assertTrue(hayhouseradioLinkButton !&#61; null);assertTrue(healLinkButton !&#61; null);assertTrue(gobackButton_hayhouse !&#61; null);assertTrue(detailView !&#61; null);}

#7.怎样对一个Service进行测试

1 /**
2 * From sdk description
3 *
4 * This test case provides a framework in which you can test Service classes
5 * in a controlled environment. It provides basic support for the lifecycle of a
6 * Service, and hooks with which you can inject various dependencies and
7 * control the environment in which your Service is tested.
8 */
9
10 public class AudioServiceTest extends ServiceTestCase {
11 private static final String TAG &#61; "-----AudioServiceTest-----";
12
13 public AudioServiceTest() {
14 super(AudioService.class);
15 }
16
17 &#64;Override
18 protected void setUp() throws Exception {
19 Log.i(TAG, "&#61;&#61;&#61;&#61;&#61;AudioServiceTest setUp Start&#61;&#61;&#61;&#61;&#61;");
20 super.setUp();
21
22 Log.i(TAG, "&#61;&#61;&#61;&#61;&#61;AudioServiceTest setUp End&#61;&#61;&#61;&#61;&#61;");
23 }
24
25 /**
26 * 2011.09.16 jack.li add......
27 * test basic startup/shutdown of Service
28 */
29 &#64;SmallTest
30 public void testStartable() {
31 Log.i(TAG, "&#43;&#43;&#43;&#43;&#43;AudioServiceTest testStartable Start&#43;&#43;&#43;&#43;&#43;");
32 Intent startIntent &#61; new Intent();
33 startIntent.setClass(getContext(), AudioService.class);
34 startService(startIntent);
35 assertNotNull(getService());
36 }
37
38 /**
39 * 2011.09.16 jack.li add......
40 * test binding to service
41 */
42 &#64;MediumTest
43 public void testBindable() {
44 Log.i(TAG, "&#43;&#43;&#43;&#43;&#43;AudioServiceTest testBindable Start&#43;&#43;&#43;&#43;&#43;");
45 Intent startIntent &#61; new Intent();
46 startIntent.setClass(getContext(), AudioService.class);
47 IBinder service &#61; bindService(startIntent);
48 assertNotNull(service);
49 }
50
51 }

#8.如何对android中数据库进行一个单元测试,这里我引用网上的一个案例
数据库的逻辑代码如下&#xff1a;

1 import java.text.SimpleDateFormat;
2 import java.util.ArrayList;
3 import java.util.Date;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Random;
8
9 import android.content.ContentValues;
10 import android.content.Context;
11 import android.database.Cursor;
12 import android.database.DatabaseUtils;
13 import android.database.sqlite.SQLiteDatabase;
14
15 import com.android.hanhan.R;
16
17 public class DatabaseService {
18 private DatabaseHelper dbOpenHelper;
19 protected static final String TBL_NAME &#61; "article";
20 protected static final String FIELD_ID &#61; "id";
21 protected static final String FIELD_TITLE &#61; "title";
22 protected static final String FIELD_CONTENT &#61; "content";
23 protected static final String FIELD_DELETE &#61; "deleted";
24 protected static final String FIELD_PUBLISHDATE &#61; "publishdate";
25 protected static final String FIELD_FAVORITE &#61; "favorite";
26 protected static final String FIELD_CLICKCOUNT &#61; "clickcount";
27 protected static final String FIELD_FAVORITEDATE &#61; "favoritedate";
28
29 //构造器&#xff0c;初始数据库服务
30 public DatabaseService(Context context) {
31 dbOpenHelper &#61; new DatabaseHelper(context);
32 }
33
34 //删除表
35 public void dropTable(String taleName) {
36 dbOpenHelper.getWritableDatabase().execSQL(
37 "DROP TABLE IF EXISTS " &#43; taleName);
38 }
39 //关闭数据库
40 public void closeDB() {
41 dbOpenHelper.getWritableDatabase().close();
42 }
43 //取得数据库TBL_NAME 表的所有数据
44 public List> fetchALLArticle() {
45 SQLiteDatabase db &#61; dbOpenHelper.getReadableDatabase();
46 List> list &#61; new ArrayList>();
47 Cursor cur &#61; db.query(TBL_NAME, new String[] {FIELD_ID, FIELD_TITLE, FIELD_CONTENT,
48 FIELD_PUBLISHDATE,FIELD_FAVORITE ,FIELD_DELETE }, null, null, null,
49 null, null);
50 list &#61; getListFromDb(list, cur);
51 return list;
52 }
53 //取得数据库TBL_NAME表的数据个数
54 public long getPageCount(){
55 SQLiteDatabase db &#61; dbOpenHelper.getReadableDatabase();
56 return DatabaseUtils.queryNumEntries(db, TBL_NAME);
57 }
58 //根据分页尺寸和页数&#xff0c;取得数据列表
59 public List> fetchCustomArticle(long pageSize, long pageID) {
60 SQLiteDatabase db &#61; dbOpenHelper.getReadableDatabase();
61 List> list &#61; new ArrayList>();
62 String sql &#61; "select * from " &#43; TBL_NAME &#43;
63 " Limit "&#43;String.valueOf((pageID-1)*pageSize)&#43;" ,"&#43;String.valueOf((pageID)*pageSize);
64 Cursor cur &#61; db.rawQuery(sql, null);
65 list &#61; getListFromDb(list, cur);
66 return list;
67 }
68 //取得数据列表方法
69 private List> getListFromDb(List> list, Cursor cur) {
70 if(cur.moveToFirst()){
71 do{
72 Map map &#61; new HashMap();
73 map &#61; addValueToMap(cur);
74 list.add(map);
75 }while(cur.moveToNext());
76 }
77 return list;
78 }
79 //将数据映射到map
80 private Map addValueToMap(Cursor cur) {
81 Map map &#61; new HashMap();
82 map.put("id", cur.getString(cur.getColumnIndex(FIELD_ID)));
83 map.put("title", cur.getString(cur.getColumnIndex(FIELD_TITLE)));
84 map.put("info", cur.getString(cur.getColumnIndex(FIELD_PUBLISHDATE)));
85 map.put("content", cur.getString(cur.getColumnIndex(FIELD_CONTENT)));
86 map.put("publishdate", cur.getString(cur.getColumnIndex(FIELD_PUBLISHDATE)));
87 map.put("favorite", cur.getString(cur.getColumnIndex(FIELD_FAVORITE)));
88 map.put("delete", cur.getString(cur.getColumnIndex(FIELD_DELETE)));
89 map.put("img", R.drawable.stop);
90 return map;
91 }
92 }

对该sqlite数据库单元测试的方法如下&#xff1a;

1 import android.test.AndroidTestCase;
2 import com.android.hanhan.util.DatabaseService;
3
4 public class DatabaseServiceTest extends AndroidTestCase{
5 private DatabaseService dbs;
6
7 &#64;Override
8 protected void setUp() throws Exception {
9 dbs &#61; new DatabaseService(getContext());
10 }
11
12 &#64;Override
13 protected void tearDown() throws Exception {
14 dbs.closeDB();
15 }
16
17 public void testPageCount() throws Exception{
18 assertEquals(12, dbs.getPageCount());
19 }
20
21 public void testFetchALLArticle() throws Exception{
22 assertEquals(12, dbs.fetchALLArticle().size());
23 }
24
25 }

#9.我在HYB项目中写的Database测试类也贴出来给大家看看

1 package com.ceosoftcenters.healyourbody.db.test;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8
9 import com.ceosoftcenters.healyourbody.sqlite.SQLiteHelper;
10 import com.ceosoftcenters.healyourbody.sqlite.vo.ProblemDetailVO;
11 import com.ceosoftcenters.healyourbody.sqlite.vo.ProblemVO;
12 import com.ceosoftcenters.healyourbody.util.ConstantsUtil;
13
14 import android.database.Cursor;
15 import android.database.sqlite.SQLiteDatabase;
16 import android.test.AndroidTestCase;
17 import android.util.Log;
18
19 /**
20 * &#64;file SQLiteHelperTest.java
21 * &#64;author Jack.Li
22 * &#64;date 2011.09.15
23 * &#64;description this class is mainly for SQLite Database&#39;s unit testing
24 * AndroidTestCase--->Extend this if you need to access Resources or other things that depend on Activity Context.
25 *
26 */
27
28 public class SQLiteHelperTest extends AndroidTestCase {
29 private static final String TAG &#61; "-----SQLiteHelperTest-----";
30
31 //declare SQLiteHelper&#39;s instance ---> testSQLiteHelper
32 private SQLiteHelper testSQLiteHelper;
33
34 //private HealYourBodyApplication hybApp;
35
36 //declare SQLiteDatabase&#39;s instance ---> database
37 SQLiteDatabase database;
38
39 //all the data from the database
40 private ArrayList problemDataSet &#61; null;
41
42 //2011.09.26 jack add......custom data for testing
43 private List> list_testSQLiteHelper &#61; null;
44
45 public static final String ITEM_PROBLEM_ID&#61; "problem_Id";
46 public static final String ITEM_PROBLEM_NAME &#61; "problem_Name";
47
48 //2011.10.12.PM jack new add...
49 public int ITEM_Number;
50
51 &#64;Override
52 protected void setUp() {
53 try {
54 super.setUp();
55 }catch (Exception e) {
56 e.printStackTrace();
57 }
58
59 Log.i(TAG, "&#61;&#61;SQLiteHelperTest setUp method is starting&#61;&#61;");
60
61 testSQLiteHelper &#61; new SQLiteHelper(getContext());
62 System.out.println("&#43;&#43;&#43;&#43;&#43;" &#43; testSQLiteHelper &#43; "&#43;&#43;&#43;&#43;&#43;");
63
64 database &#61; SQLiteDatabase.openOrCreateDatabase(getContext().getFilesDir().getAbsolutePath() &#43; ConstantsUtil.HEAL_YOUR_BODY_DBFILE_PATH, null);
65 System.out.println("&#43;&#43;&#43;&#43;&#43;" &#43; database &#43; "&#43;&#43;&#43;&#43;&#43;");
66
67 list_testSQLiteHelper &#61; new ArrayList>();
68 getListValue(list_testSQLiteHelper);
69
70 problemDataSet &#61; new ArrayList();
71 setProblemDataSet(problemDataSet);
72
73 Log.i(TAG, "&#61;&#61;SQLiteHelperTest setUp method is ending&#61;&#61;");
74
75 }
76
77 //set values for problemDataSet
78 public void setProblemDataSet(ArrayList problemDataSet) {
79 //query database file to set data for list view
80 SQLiteDatabase database &#61; SQLiteDatabase.openOrCreateDatabase(getContext().getFilesDir().getAbsolutePath() &#43; ConstantsUtil.HEAL_YOUR_BODY_DBFILE_PATH, null);
81
82 //query all data from the table bookdata -----> String sql &#61; "select id,problem from bookdata";
83 Cursor cursor &#61; database.rawQuery(ConstantsUtil.QUERY_ALL_ITEMS_ID_PROBLEM_SQL,null);
84 if (cursor.getCount() > 0) {
85 cursor.moveToFirst();
86 ProblemVO pd &#61; null;
87 while(!cursor.isLast()) {
88 int id &#61; cursor.getInt(0);
89 String problemName &#61; cursor.getString(1);
90 pd &#61; new ProblemVO(id,problemName);
91 problemDataSet.add(pd);
92 cursor.moveToNext();
93 }
94 int id &#61; cursor.getInt(0);
95 String problemName &#61; cursor.getString(1);
96 pd &#61; new ProblemVO(id,problemName);
97 problemDataSet.add(pd);
98 //get the problemDtaSet&#39;s size -----> because it is a manually edit database,some items do not be used.
99 //So the last id number is not the problemDataSet&#39;s size
100 //get the problemDataSet&#39;s size
101 System.out.println("**********" &#43; problemDataSet.size() &#43; "**********");
102 ITEM_Number &#61; problemDataSet.size();
103 }
104 cursor.close();
105 database.close();
106 }
107
108 //custom list values for testing
109 public void getListValue(List> list_testSQLiteHelper) {
110 //I don&#39;t know why the last item is -----> "Itis" -----> solved
111 //we think "Itis" is a dirty data
112 //the custom data&#39;s number are 20
113 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("5", "Acne"));
114 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("11", "Aids"));
115 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("16", "Amnesia"));
116 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("22", "Anus"));
117 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("48", "Bad Breath"));
118 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("54", "Birth"));
119 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("64", "Blood"));
120 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("80", "Brain"));
121 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("117", "Coma"));
122 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("134", "Death"));
123 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("169", "Fat"));
124 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("177", "Fever"));
125 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("186", "Fistula"));
126 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("198", "Gastritis"));
127 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("234", "Hypertension"));
128 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("252", "Itching"));
129 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("260", "Knee"));
130 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("331", "Petit Mal"));
131 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("364", "Root Canal"));
132 list_testSQLiteHelper.add(SQLiteHelperTest.getHashMapValue("444", "Wrist"));
133 }
134
135 //jack new add...2011.09.26.am
136 public static HashMap getHashMapValue(String problem_Id,String problem_Name) {
137 HashMap hm_testSQLiteHelper &#61; new HashMap();
138 hm_testSQLiteHelper.put(ITEM_PROBLEM_ID, problem_Id);
139 hm_testSQLiteHelper.put(ITEM_PROBLEM_NAME, problem_Name);
140
141 return hm_testSQLiteHelper;
142 }
143
144 public void testGetProblemDetailById() {
145 //total item&#39;s number is 440 -----> get the size 2011.10.08.am
146 //iterator the list_testSQLiteHelper,to get per item&#39;s id and name
147 Iterator> it &#61; list_testSQLiteHelper.iterator();
148 while(it.hasNext()) {
149 Map hm &#61; it.next();
150 String problem_Id &#61; (String)hm.get(ITEM_PROBLEM_ID);
151 String Problem_Name &#61; (String)hm.get(ITEM_PROBLEM_NAME);
152
153 ProblemDetailVO pdvo &#61; testSQLiteHelper.getProblemDetailById(problem_Id, Problem_Name);
154 //perform toString() method
155 System.out.println(">>>>>" &#43; pdvo &#43; "<<<<<");
156 }
157 System.out.println("&#64;&#64;&#64;" &#43;"iterator method is ending......" &#43; "&#64;&#64;&#64;");
158
159 }
160
161 public void testGetProblemDetailByIdAllData() {
162 for(ProblemVO pd: problemDataSet) {
163 String problemId &#61; pd.getId() &#43; "";
164 String problemName &#61; pd.getProblemName();
165 ProblemDetailVO pdvo &#61; testSQLiteHelper.getProblemDetailById(problemId, problemName);
166
167 System.out.println(">>>>>" &#43; pdvo &#43; "<<<<<");
168 }
169 }
170
171 //test the data count ---> sum
172 public void testSetProblemDataSetSize() throws Exception{
173 //put all the ProblemVO instance into the problemDataSet ArrayList
174 //problemDataSet &#61; new HealYourBodyApplication().getProblemDataSet();
175 assertEquals(440, problemDataSet.size());
176 assertEquals(false, problemDataSet.size() &#61;&#61; 445);
177 assertEquals(false, problemDataSet.size() &#61;&#61; 335);
178 }
179
180 &#64;Override
181 protected void tearDown() throws Exception {
182 Log.i(TAG, "&#61;&#61;SQLiteHelperTest tearDown method is starting&#61;&#61;");
183 //close the resource
184 database.close();
185 super.tearDown();
186 }
187
188 }

至此我对android单元测试的研究告一段落.以后有机会会继续深入学习的.

 

2011.10.21.pm

jack.li

QQ:523072842
Email:523072842&#64;qq.com

转:https://www.cnblogs.com/jackxlee/archive/2011/10/21/2220395.html



推荐阅读
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了10分钟了解Android的事件分发相关的知识,希望对你有一定的参考价值。什么是事件分发?大家 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • Android源码中的Builder模式及其作用
    本文主要解释了什么是Builder模式以及其作用,并结合Android源码来分析Builder模式的实现。Builder模式是将产品的设计、表示和构建进行分离,通过引入建造者角色,简化了构建复杂产品的流程,并且使得产品的构建可以灵活适应变化。使用Builder模式可以解决开发者需要关注产品表示和构建步骤的问题,并且当构建流程发生变化时,无需修改代码即可适配新的构建流程。 ... [详细]
  • WPF之Binding初探
      初学wpf,经常被Binding搞晕,以下记录写Binding的基础。首先,盗用张图。这图形象的说明了Binding的机理。对于Binding,意思是数据绑定,基本用法是:1、 ... [详细]
author-avatar
靈幻雪月
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有