request = mQueue.take();2.发起网络请求
NetworkResponse networkResponse = mNetwork.performRequest(request);3.将网络响应加入缓存
mCache.put(request.getCacheKey(), response.cacheEntry);
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request request;
while (true) {
try {
// Take a request from the queue.
request = mQueue.take();//1.从请求队列中取出一个网络请求,mQueue是BlockingQueue<Request>的实现类
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("network-queue-take");
// If the request was cancelled already, do not perform the
// network request.
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}
// Tag the request (if API >= 14)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
}
// Perform the network request.
NetworkResponse networkResponse = mNetwork.performRequest(request);//2.发起网络请求
request.addMarker("network-http-complete");
// If the server returned 304 AND we delivered a response already,
// we're done -- don't deliver a second identical response.
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// Parse the response here on the worker thread.
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);//3.将网络响应加入缓存
request.addMarker("network-cache-written");
}
// Post the response back.
request.markDelivered();
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
mDelivery.postError(request, new VolleyError(e));
}
}
}
BlockingQueue implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms of concurrency control. /** The queue of requests to service. */
private final BlockingQueue<Request> mQueue;
/** The network interface for processing requests. */
private final Network mNetwork;
/** The cache to write to. */
private final Cache mCache;
/** For posting responses and errors. */
private final ResponseDelivery mDelivery;
/** Used for telling us to die. */
private volatile boolean mQuit = false;
/**
* Creates a new network dispatcher thread. You must call {@link #start()}
* in order to begin processing.
*
* @param queue Queue of incoming requests for triage
* @param network Network interface to use for performing requests
* @param cache Cache interface to use for writing responses to cache
* @param delivery Delivery interface to use for posting responses
*/
public NetworkDispatcher(BlockingQueue<Request> queue,
Network network, Cache cache,
ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
}NetworkDispatcher构造函数的几个参数都是接口,而run方法则使用这些策略类方法实现了算法的主体流程,具体实现有些留给了开发者,有些则是框架实现。比如ImageCache作为一级缓存的Cache方法留给了开发者实现,由开发者控制具体的缓存策略,当然Volley建议我们使用LRUCache作为L1缓存的实现。/**
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
*
* @param cache A Cache to use for persisting responses to disk
* @param network A Network interface for performing HTTP requests
* @param threadPoolSize Number of network dispatcher threads to create
* @param delivery A ResponseDelivery interface for posting responses and errors
*/
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
/**
* Starts the dispatchers in this queue.
*/
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}使用Volley时,可以覆写Activity或者Fragment中的onScrollStateChanged,如果处于AbsListView.OnScrollListener.SCROLL_STATE_FLING的状态,则imageLoader.stopProcessingQueue()(停止网络图片加载)。imageLoader是NetworkImageView的一个引用,负责加载图片,这样在快速滑动时就不会加载图片。
另外也同样可以在Adapter中设置标志位,表示是否正在快速滑动,如果正在快速滑动,Adapter中的getView只需要把TextView等简单数据显示出来,把复杂逻辑和onClickListener等移到非Fling状态时才设置。
关于Volley的介绍可以看这篇博客:http://blog.csdn.net/t12x3456/article/details/9221611
层层嵌套的布局会花费很多渲染时间。
一个常见的不需要嵌套的例子是使用FrameLayout作为布局的单一根节点,当该布局被添加到一个父容器时,它就会成为冗余。更好的做法是使用merge标签。当包含有merge标签的布局被添加到另一个布局时,该布局的merge节点会被删除,而该布局的子View会被直接添加到新的父布局中。
include标签可以把一个布局的内容插入到另一个布局。利用include标签可以在垂直和水平方向的不同布局中共享大多数UI布局。
View Stub是一个可见的、大小为0的View,它就像一个延迟填充的include标签,只有在显示调用inflate方法或者被置为可见是,这个stub才被填充。
更多详解介绍可以参考:《Android4高级编程》P90,《Android优化技术详解》P76
(1)复用convertView。convertView是ListView的RecycleBin内部类帮我们缓存的,如果ListView的不同列表项有不同的类型,可以在Apdater的getViewTypeCount中返回类型数,ListView会根据不同类别分别缓存。可以看我之前对ListView源代码的分析:http://blog.csdn.net/mba16c35/article/details/43638793
(2)使用ViewHolder。新建列表项视图的各项子视图都存在ViewHolder中,然后setTag,下次直接通过
ItemViewHolder holder = (ItemViewHolder) convertView.getTag();就省去了findViewById的步骤。
下面是一段示例代码。XXNetworkImageView继承Volley中的NetworkImageView。
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView==null)
{
convertView = mInflater.inflate(layoutID, null);
ItemViewHolder holder = new ItemViewHolder();
holder.bookCover = (XXNetworkImageView) convertView.findViewById(R.id.book_booklist_cover);
holder.bookName = (TextView) convertView.findViewById(R.id.book_booklist_name);
holder.bookClickNumber = (TextView) convertView.findViewById(R.id.book_booklist_clicknumber);
holder.bookType = (TextView) convertView.findViewById(R.id.book_booklist_type);
holder.bookAuthor = (TextView) convertView.findViewById(R.id.book_booklist_author);
holder.bookState = (ImageView) convertView.findViewById(R.id.book_booklist_state);
convertView.setTag(holder);
}
bindView(convertView, position);
return convertView;
}
private void bindView(View convertView, int position) {
ItemViewHolder holder = (ItemViewHolder) convertView.getTag();
String imageUrl = (String) Util.IMG_URL_PREFIX + bookList.get(position).getImgUrl();
String currentUrl = holder.bookCover.getUrl();
if (currentUrl == null || !currentUrl.equals(imageUrl)) {
if (mContext != null) {
holder.bookCover.setImageUrl(imageUrl, imageLoader, Util.dip2px(mContext, 95));
} else {
holder.bookCover.setImageUrl(imageUrl, imageLoader);
}
}
holder.bookName.setText(String.valueOf(bookList.get(position).getName()));
holder.bookClickNumber.setText(String.valueOf(bookList.get(position).getFreePage()));
holder.bookType.setText("类型: "+ String.valueOf(bookList.get(position).getTypes()));
holder.bookAuthor.setText("作者: " + String.valueOf(bookList.get(position).getAuthor()));
if(String.valueOf(bookList.get(position).getScale()).equals("0"))
holder.bookState.setImageResource(R.drawable.tag0);
// else if(String.valueOf(bookListData.get(position).get("state")).equals("1"))
// holder.bookState.setImageResource(R.drawable.tag);
}
static class ItemViewHolder {
XXNetworkImageView bookCover;
TextView bookName;
TextView bookClickNumber;
TextView bookType;
TextView bookAuthor;
ImageView bookState;
}优化ListView中的网络图片加载 及 Volley库源码分析
原文:http://blog.csdn.net/mba16c35/article/details/43707407