前几天看了github上面的例子,参照它的实现,自己又稍微改了一点,往项目里面增加了一个上拉加载更多功能。具体的实现如下:

首先要重写ListView:

  1. import android.content.Context;
  2. import android.util.AttributeSet;
  3. import android.widget.AbsListView;
  4. import android.widget.HeaderViewListAdapter;
  5. import android.widget.ListAdapter;
  6. import android.widget.ListView;
  7.  
  8. import java.util.List;
  9.  
  10. import njucm.edu.loadmore.activities.LoadingView;
  11. import njucm.edu.loadmore.adapters.PagingBaseAdapter;
  12.  
  13. /**
  14. * Created by Mesogene on 10/9/15.
  15. */
  16. public class LoadListView extends ListView {
  17.  
  18. private OnScrollListener onScrollListener = null;
  19. private PageEnableListener pageEnableListener = null;
  20. LoadingView loadListView = null;
  21. private boolean isLoading;
  22. private boolean hasMoreItem;
  23. private int lastVisibleItem; //最后一个可见的项
  24. private int totalItemCount; //总的项数
  25.  
  26. public LoadListView(Context context) {
  27. super(context);
  28. init();
  29. }
  30.  
  31. public LoadListView(Context context, AttributeSet attrs) {
  32. super(context, attrs);
  33. init();
  34. }
  35.  
  36. public LoadListView(Context context, AttributeSet attrs, int defStyleAttr) {
  37. super(context, attrs, defStyleAttr);
  38. init();
  39. }
  40.  
  41. public void setPageEnableListener(PageEnableListener pageEnableListener) {
  42. this.pageEnableListener = pageEnableListener;
  43. }
  44.  
  45. public boolean isLoading() {
  46. return isLoading;
  47. }
  48.  
  49. public void setIsLoading(boolean isLoading) {
  50. this.isLoading = isLoading;
  51. }
  52.  
  53. public boolean isHasMoreItem() {
  54. return hasMoreItem;
  55. }
  56.  
  57. public void setHasMoreItem(boolean hasMoreItem) {
  58. this.hasMoreItem = hasMoreItem;
  59. if(!this.hasMoreItem){ //如果没有更多项,移除底部
  60. removeFooterView(loadListView);
  61. }
  62. else if(findViewById(R.id.loading_view) == null){
  63. addFooterView(loadListView);
  64. ListAdapter adapter = ((HeaderViewListAdapter) getAdapter()).getWrappedAdapter();
  65. setAdapter(adapter);
  66. }
  67. }
  68.  
  69. /**
  70. * 在下载任务完成之后去调用这个方法
  71. * @param hasMoreItem 是否还有更多项
  72. * @param newItems 新的项
  73. */
  74. public void onFinsihLoading(boolean hasMoreItem, List<? extends Object> newItems){
  75. setHasMoreItem(hasMoreItem);
  76. setIsLoading(false); //下载任务完成后,把loading设置成false
  77. if(newItems != null && newItems.size() >0){
  78. ListAdapter adapter = ((HeaderViewListAdapter)getAdapter()).getWrappedAdapter(); //获取这个listview的adapter
  79. if(adapter instanceof PagingBaseAdapter){
  80. ((PagingBaseAdapter) adapter).addMoreItems(newItems); //添加项目,包含notify方法
  81. }
  82. }
  83. }
  84. /**
  85. * 初始化listview的操作
  86. */
  87. private void init(){
  88. isLoading = false;
  89. loadListView = new LoadingView(getContext());
  90. addFooterView(loadListView);
  91. super.setOnScrollListener(new OnScrollListener() {
  92. @Override
  93. public void onScrollStateChanged(AbsListView absListView, int scrollState) {
  94. if(onScrollListener != null){
  95. onScrollListener.onScrollStateChanged(absListView, scrollState);
  96. }
  97. /**
  98. * 当你的listview移动到底部的时候,即你看到的最后一项等于总的项数,已经停止滚动 没有正在加载并且还有更多项
  99. * 的时候会被执行
  100. */
  101. if(lastVisibleItem == totalItemCount && scrollState == SCROLL_STATE_IDLE && !isLoading && hasMoreItem){
  102. if(pageEnableListener != null){
  103. isLoading = true; //执行之后的状态就是loading
  104. pageEnableListener.onLoadMoreItems(); //调用回调方法
  105. }
  106. }
  107. }
  108.  
  109. @Override
  110. public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totleItem) {
  111. //Dispatch to child OnScrollListener
  112. if (onScrollListener != null) {
  113. onScrollListener.onScroll(absListView, firstVisibleItem, visibleItemCount, totleItem);
  114. }
  115. lastVisibleItem = firstVisibleItem + visibleItemCount; //最后看到的一项
  116. totalItemCount = totleItem; //总的项数
  117. }
  118. });
  119.  
  120. }
  121.  
  122. @Override
  123. public void setOnScrollListener(OnScrollListener onScrollListener) {
  124. this.onScrollListener = onScrollListener;
  125. }
  126.  
  127. public interface PageEnableListener{
  128. public void onLoadMoreItems();
  129. }
  130.  
  131. }

我们可以看到还要加一个loadingview的,就是你的正在加载界面,这个界面会被动态添加到你的footview里面的:

  1. package njucm.edu.loadmore.activities;
  2.  
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.widget.LinearLayout;
  6.  
  7. import njucm.edu.loadmore.R;
  8.  
  9. /**
  10. * Created by Mesogene on 10/10/15.
  11. */
  12. public class LoadingView extends LinearLayout {
  13.  
  14. public LoadingView(Context context) {
  15. super(context);
  16. init();
  17. }
  18.  
  19. public LoadingView(Context context, AttributeSet attrs) {
  20. super(context, attrs);
  21. init();
  22. }
  23.  
  24. public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
  25. super(context, attrs, defStyleAttr);
  26. init();
  27. }
  28.  
  29. public void init(){
  30. inflate(getContext(), R.layout.loadinflinear, this);
  31. }
  32.  
  33. }

只是简单重写了一下LinearLayout, 下面只要写一个loading的不局文件就行了

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:orientation="horizontal" android:layout_width="match_parent"
  3. android:layout_height="match_parent"
  4. android:gravity="center"
  5. android:layout_margin="@dimen/dp_10"
  6. android:id="@+id/loading_view">
  7.  
  8. <ProgressBar
  9. android:id="@+id/video_item_image"
  10. style="?android:progressBarStyle"
  11. android:layout_width="@dimen/loading_view_progress_size"
  12. android:layout_height="@dimen/loading_view_progress_size"
  13. android:layout_marginRight="@dimen/loading_view_margin_right"
  14. android:indeterminate="true"/>
  15. <TextView
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:text="@string/loading"
  19. android:layout_gravity="center"
  20. android:textColor="@color/material_blue_grey_800"
  21. android:textSize="@dimen/sp_18"/>
  22.  
  23. </LinearLayout>

这样基本就已经好了,那么还有一个listview的父类的适配器要自己写一下:

  1. import android.widget.BaseAdapter;
  2. import android.widget.ListAdapter;
  3.  
  4. import java.util.ArrayList;
  5. import java.util.List;
  6.  
  7. import njucm.edu.loadmore.LoadListView;
  8.  
  9. /**
  10. * Created by Mesogene on 10/12/15.
  11. */
  12. public abstract class PagingBaseAdapter<T> extends BaseAdapter {
  13.  
  14. protected List<T> items = null;
  15.  
  16. public PagingBaseAdapter(List<T> items) {
  17. this.items = items;
  18. }
  19.  
  20. public PagingBaseAdapter(){
  21. this.items = new ArrayList<>();
  22. }
  23.  
  24. public void addMoreItems(List<T> items){
  25. this.items.addAll(items); //把新的项添加到listview里面
  26. notifyDataSetChanged(); //更新布局
  27. }
  28.  
  29. }

这样之后,你自己的listviewAdapter就可以继承这个类,你的adapter拥有绘制每一个listitem的功能和添加下一页数据项的功能。

  1. package njucm.edu.loadmore.adapters;
  2.  
  3. import android.view.LayoutInflater;
  4. import android.view.View;
  5. import android.view.ViewGroup;
  6. import android.widget.TextView;
  7.  
  8. import java.util.List;
  9.  
  10. /**
  11. * Created by Mesogene on 10/12/15.
  12. */
  13. public class MyListAdapter extends PagingBaseAdapter<String> {
  14.  
  15. @Override
  16. public int getCount() {
  17. return items.size();
  18. }
  19.  
  20. @Override
  21. public String getItem(int position) {
  22. return items.get(position);
  23. }
  24.  
  25. @Override
  26. public long getItemId(int position) {
  27. return position;
  28. }
  29.  
  30. @Override
  31. public View getView(int position, View view, ViewGroup viewGroup) {
  32. TextView textView;
  33. String text = getItem(position);
  34. if(view != null){
  35. textView = (TextView) view;
  36. }else {
  37. textView = (TextView) LayoutInflater.from(viewGroup.getContext()).inflate(android.R.layout.simple_list_item_1, null);
  38. }
  39. textView.setText(text);
  40. return textView;
  41. }
  42. }

最后就是如何使用了,再onCreate() 或者 onCreateView() 添加如下代码,我们发现它有一个异步加载的过程,使用到了线程

  1. li.setAdapter(adapter);
  2. li.setHasMoreItem(true);
  3. li.setPageEnableListener(new LoadListView.PageEnableListener() {
  4. @Override
  5. public void onLoadMoreItems() {
  6. if(pager < 3){
  7. new CountryAsyncTask().execute();
  8. }else{
  9. li.onFinsihLoading(false, null);
  10. }
  11. }
  12. });
  1. private class CountryAsyncTask extends SafeAsyncTask<List<String>>{
  2. @Override
  3. public List<String> call() throws Exception { //模拟后台下载数据
  4. List result = null;
  5. switch (pager){
  6. case 0:
  7. result = firstList;
  8. break;
  9. case 1:
  10. result = secondList;
  11. break;
  12. case 2:
  13. result = thirdList;
  14. break;
  15. }
  16. Thread.sleep(3000);
  17. return result;
  18. }
  19.  
  20. @Override
  21. protected void onSuccess(List<String> strings) throws Exception {
  22. super.onSuccess(strings);
  23. pager++;
  24. li.onFinsihLoading(true, strings); //下载成功之后调用的方法,更新UI
  25. }
  26. }

这里面可能要自己添加一些数据在firstlist等里面。  还有下面是这个类似于AsyncTask但又不是的,这个类的代码如下

  1. package njucm.edu.loadmore.activities;
  2.  
  3. import android.os.Handler;
  4. import android.os.Looper;
  5. import android.util.Log;
  6.  
  7. import java.io.InterruptedIOException;
  8. import java.util.ArrayList;
  9. import java.util.Arrays;
  10. import java.util.concurrent.Callable;
  11. import java.util.concurrent.CountDownLatch;
  12. import java.util.concurrent.Executor;
  13. import java.util.concurrent.Executors;
  14. import java.util.concurrent.FutureTask;
  15.  
  16. /**
  17. * A class similar but unrelated to android's {@link android.os.AsyncTask}.
  18. * <p/>
  19. * Unlike AsyncTask, this class properly propagates exceptions.
  20. * <p/>
  21. * If you're familiar with AsyncTask and are looking for {@link android.os.AsyncTask#doInBackground(Object[])},
  22. * we've named it {@link #call()} here to conform with java 1.5's {@link java.util.concurrent.Callable} interface.
  23. * <p/>
  24. * Current limitations: does not yet handle progress, although it shouldn't be
  25. * hard to add.
  26. * <p/>
  27. * If using your own executor, you must call future() to get a runnable you can execute.
  28. *
  29. * @param <ResultT>
  30. */
  31. public abstract class SafeAsyncTask<ResultT> implements Callable<ResultT> { //Callable可以返回任意类型。1.5 以后加入
  32. public static final int DEFAULT_POOL_SIZE = 25; //默认的线程池的大小是25
  33. protected static final Executor DEFAULT_EXECUTOR = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE); //利用线程池
  34.  
  35. protected Handler handler;
  36. protected Executor executor;
  37. protected StackTraceElement[] launchLocation;
  38. protected FutureTask<Void> future;
  39.  
  40. /**
  41. * Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE) and
  42. * Handler to new Handler()
  43. */
  44. public SafeAsyncTask() {
  45. this.executor = DEFAULT_EXECUTOR;
  46. }
  47.  
  48. /**
  49. * Sets executor to Executors.newFixedThreadPool(DEFAULT_POOL_SIZE)
  50. */
  51. public SafeAsyncTask(Handler handler) {
  52. this.handler = handler;
  53. this.executor = DEFAULT_EXECUTOR; //线程池用默认的设置
  54. }
  55.  
  56. /**
  57. * Sets Handler to new Handler()
  58. */
  59. public SafeAsyncTask(Executor executor) {
  60. this.executor = executor;
  61. }
  62.  
  63. public SafeAsyncTask(Handler handler, Executor executor) {
  64. this.handler = handler;
  65. this.executor = executor;
  66. }
  67.  
  68. public FutureTask<Void> future() {
  69. future = new FutureTask<Void>(newTask());
  70. return future;
  71. }
  72.  
  73. public SafeAsyncTask<ResultT> executor(Executor executor) {
  74. this.executor = executor;
  75. return this;
  76. }
  77.  
  78. public Executor executor() {
  79. return executor;
  80. }
  81.  
  82. public SafeAsyncTask<ResultT> handler(Handler handler) {
  83. this.handler = handler;
  84. return this;
  85. }
  86.  
  87. public Handler handler() {
  88. return handler;
  89. }
  90.  
  91. public void execute() {
  92. execute(Thread.currentThread().getStackTrace());
  93. }
  94.  
  95. protected void execute(StackTraceElement[] launchLocation) {
  96. this.launchLocation = launchLocation;
  97. executor.execute(future());
  98. }
  99.  
  100. public boolean cancel(boolean mayInterruptIfRunning) {
  101. if (future == null) throw new UnsupportedOperationException("You cannot cancel this task before calling future()");
  102.  
  103. return future.cancel(mayInterruptIfRunning);
  104. }
  105.  
  106. /**
  107. * @throws Exception, captured on passed to onException() if present.
  108. */
  109. protected void onPreExecute() throws Exception {
  110. }
  111.  
  112. /**
  113. * @param t the result of {@link #call()}
  114. * @throws Exception, captured on passed to onException() if present.
  115. */
  116. @SuppressWarnings({"UnusedDeclaration"})
  117. protected void onSuccess(ResultT t) throws Exception {
  118. }
  119.  
  120. /**
  121. * Called when the thread has been interrupted, likely because
  122. * the task was canceled.
  123. * <p/>
  124. * By default, calls {@link #onException(Exception)}, but this method
  125. * may be overridden to handle interruptions differently than other
  126. * exceptions.
  127. *
  128. * @param e an InterruptedException or InterruptedIOException
  129. */
  130. protected void onInterrupted(Exception e) {
  131. onException(e);
  132. }
  133.  
  134. /**
  135. * Logs the exception as an Error by default, but this method may
  136. * be overridden by subclasses.
  137. *
  138. * @param e the exception thrown from {@link #onPreExecute()}, {@link #call()}, or {@link #onSuccess(Object)}
  139. * @throws RuntimeException, ignored
  140. */
  141. protected void onException(Exception e) throws RuntimeException {
  142. onThrowable(e);
  143. }
  144.  
  145. protected void onThrowable(Throwable t) throws RuntimeException {
  146. Log.e("roboguice", "Throwable caught during background processing", t);
  147. }
  148.  
  149. /**
  150. * @throws RuntimeException, ignored
  151. */
  152. protected void onFinally() throws RuntimeException {
  153. }
  154.  
  155. protected Task<ResultT> newTask() {
  156. return new Task<ResultT>(this);
  157. }
  158.  
  159. public static class Task<ResultT> implements Callable<Void> {
  160. protected SafeAsyncTask<ResultT> parent;
  161. protected Handler handler;
  162.  
  163. public Task(SafeAsyncTask<ResultT> parent) {
  164. this.parent = parent;
  165. this.handler = parent.handler != null ? parent.handler : new Handler(Looper.getMainLooper());
  166. }
  167.  
  168. public Void call() throws Exception {
  169. try {
  170. doPreExecute();
  171. doSuccess(doCall());
  172.  
  173. } catch (final Exception e) {
  174. try {
  175. doException(e);
  176. } catch (Exception f) {
  177. // logged but ignored
  178. Log.e("BACKGROUND_TASK", "Exception in", f);
  179. }
  180.  
  181. } catch (final Throwable t) {
  182. try {
  183. doThrowable(t);
  184. } catch (Exception f) {
  185. // logged but ignored
  186. Log.e("BACKGROUND_TASK", "Exception in", f);
  187. }
  188. } finally {
  189. doFinally();
  190. }
  191.  
  192. return null;
  193. }
  194.  
  195. protected void doPreExecute() throws Exception {
  196. postToUiThreadAndWait(new Callable<Object>() {
  197. public Object call() throws Exception {
  198. parent.onPreExecute();
  199. return null;
  200. }
  201. });
  202. }
  203.  
  204. protected ResultT doCall() throws Exception {
  205. return parent.call();
  206. }
  207.  
  208. protected void doSuccess(final ResultT r) throws Exception {
  209. postToUiThreadAndWait(new Callable<Object>() {
  210. public Object call() throws Exception {
  211. parent.onSuccess(r);
  212. return null;
  213. }
  214. });
  215. }
  216.  
  217. protected void doException(final Exception e) throws Exception {
  218. if (parent.launchLocation != null) {
  219. final ArrayList<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
  220. stack.addAll(Arrays.asList(parent.launchLocation));
  221. e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
  222. }
  223. postToUiThreadAndWait(new Callable<Object>() {
  224. public Object call() throws Exception {
  225. if (e instanceof InterruptedException || e instanceof InterruptedIOException) parent.onInterrupted(e);
  226. else parent.onException(e);
  227. return null;
  228. }
  229. });
  230. }
  231.  
  232. protected void doThrowable(final Throwable e) throws Exception {
  233. if (parent.launchLocation != null) {
  234. final ArrayList<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
  235. stack.addAll(Arrays.asList(parent.launchLocation));
  236. e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
  237. }
  238. postToUiThreadAndWait(new Callable<Object>() {
  239. public Object call() throws Exception {
  240. parent.onThrowable(e);
  241. return null;
  242. }
  243. });
  244. }
  245.  
  246. protected void doFinally() throws Exception {
  247. postToUiThreadAndWait(new Callable<Object>() {
  248. public Object call() throws Exception {
  249. parent.onFinally();
  250. return null;
  251. }
  252. });
  253. }
  254.  
  255. /**
  256. * Posts the specified runnable to the UI thread using a handler,
  257. * and waits for operation to finish. If there's an exception,
  258. * it captures it and rethrows it.
  259. *
  260. * @param c the callable to post
  261. * @throws Exception on error
  262. */
  263. protected void postToUiThreadAndWait(final Callable c) throws Exception {
  264. final CountDownLatch latch = new CountDownLatch(1);
  265. final Exception[] exceptions = new Exception[1];
  266.  
  267. // Execute onSuccess in the UI thread, but wait
  268. // for it to complete.
  269. // If it throws an exception, capture that exception
  270. // and rethrow it later.
  271. handler.post(new Runnable() {
  272. public void run() {
  273. try {
  274. c.call();
  275. } catch (Exception e) {
  276. exceptions[0] = e;
  277. } finally {
  278. latch.countDown();
  279. }
  280. }
  281. });
  282.  
  283. // Wait for onSuccess to finish
  284. latch.await();
  285.  
  286. if (exceptions[0] != null) throw exceptions[0];
  287.  
  288. }
  289.  
  290. }
  291.  
  292. }

好了,最简单的上拉加载就是这个样子了。我已经把它集成进了自己的项目里面。

Android 上拉加载更多功能的更多相关文章

  1. Android 开发 上拉加载更多功能实现

    实现思维 开始之前先废话几句,Android系统没有提供上拉加载的控件,只提供了下拉刷新的SwipeRefreshLayout控件.这个控件我们就不废话,无法实现上拉刷新的功能.现在我们说说上拉加载更 ...

  2. Flutter移动电商实战 --(20)首页上拉加载更多功能的制作

    这节课学习一下上拉加载效果,其实现在上拉加载的插件有很多,但是还没有一个插件可以说完全一枝独秀,我也找了一个插件,这个插件的优点就是服务比较好,作者能及时回答大家的问题.我觉的选插件也是选人,人对了, ...

  3. android ListView上拉加载更多 下拉刷新功能实现(采用pull-to-refresh)

    Android实现上拉加载更多功能以及下拉刷新功能, 采用了目前比较火的PullToRefresh,他是目前实现比较好的下拉刷新的类库. 目前他支持的控件有:ListView, ExpandableL ...

  4. Android5.0新特性:RecyclerView实现上拉加载更多

    RecyclerView是Android5.0以后推出的新控件,相比于ListView可定制性更大,大有取代ListView之势.下面这篇博客主要来实现RecyclerView的上拉加载更多功能. 基 ...

  5. SwipeRefreshLayout详解和自定义上拉加载更多

    个人主页 演示Demo下载 本文重点介绍了SwipeRefreshLayout的使用和自定View继承SwipeRefreshLayout添加上拉加载更多的功能. 介绍之前,先来看一下SwipeRef ...

  6. 实现上拉加载更多的SwipeRefreshLayout

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...

  7. 自定义ListView下拉刷新上拉加载更多

    自定义ListView下拉刷新上拉加载更多 自定义RecyclerView下拉刷新上拉加载更多 Listview现在用的很少了,基本都是使用Recycleview,但是不得不说Listview具有划时 ...

  8. Android中自定义ListView实现上拉加载更多和下拉刷新

    ListView是Android中一个功能强大而且很常用的控件,在很多App中都有ListView的下拉刷新数据和上拉加载更多这个功能.这里我就简单记录一下实现过程. 实现这个功能的方法不止一个,Gi ...

  9. android ListView下拉刷新 上拉加载更多

    背景 最近在公司的项目中要使用到ListView的下拉刷新和上拉加载更多(貌似现在是个项目就有这个功能!哈哈),其实这个东西GitHub上很多,但是我感觉那些框架太大,而且我这个项目只用到了ListV ...

随机推荐

  1. 8 Things Every Person Should Do Before 8 A.M.

    https://medium.com/@benjaminhardy/8-things-every-person-should-do-before-8-a-m-cc0233e15c8d 1. Get A ...

  2. 编程概念--使用async和await的异步编程

    Asynchronous Programming with Async and Await You can avoid performance bottlenecks and enhance the ...

  3. chrome插件background.js 和 popup.js 交互

    要实现background.js 和 popup.js 之间的交互,首先需要先配置好 manifest.json文件,如: "background":{ //"page& ...

  4. NOI2002robot

    这题又是纯数论题…… 独立数就是欧拉函数,政客和军人的含义已经说的很清楚了,学者是最多的…… 首先,如果我们知道了政客和军人的答案,那就只要用n的所有因子的欧拉函数值减去这两个值,然后取模就行了. 但 ...

  5. Microsoft强大团队(源代码)管理工具--TFS2010 与vs结合

    今天看了与vs 集成原理工具 TFS 2010, 角色分配.项目管理.开发源代码管理.任务分配管理.测试文档管理及跟踪等管理流程.代码版本的分支与合并等等,功能好强大啊. 以下将其安装配置简要介绍(以 ...

  6. Socket编程(九)

    此为网络编程的一个系列,后续会把内容补上.....

  7. 统一Matlab下不同子图的色标colorbar

    Reference:http://www.mathworks.com/matlabcentral/answers/100950-how-can-i-have-a-standard-colorbar-f ...

  8. 多线程程序设计学习(7)read-write lock pattern

    Read-Write Lock Pattern[读写]一:Read-Write Lock Pattern的参与者--->读写锁--->数据(共享资源)--->读线程--->写线 ...

  9. 软件测试模型汇总-V模型,W模型,X模型,H模型

    V模型 在软件测试方面,V模型是最广为人知的模型,尽管很多富有实际经验的测试人员还是不太熟悉V模型,或者其它的模型.V模型已存在了很长时间,和瀑布开发模型有着一些共同的特性,由此也和瀑布模型一样地受到 ...

  10. 黑盒测试用例设计方法&理论结合实际 -> 判定表驱动法

    一. 概念 判定表是分析和表达多逻辑条件下执行不同操作的情况的工具. 二. 判定表驱动法的应用 判定表的优点: a. 能够将复杂的问题按照各种可能的情况全部列举出来,简明并避免遗漏.因此,利用判定表能 ...