网站 白名单,wordpress主题布局教程,互联网 网站定制,昌吉 建设局 网站概述
RecyclerView 是 Android 中用于高效显示大量数据的视图组件#xff0c;它是 ListView 的升级版本#xff0c;支持更灵活的布局和功能。
我们创建一个RecyclerView的Adapter#xff1a;
public class MyRecyclerView extends RecyclerView.AdapterMyRecyclerVie…概述
RecyclerView 是 Android 中用于高效显示大量数据的视图组件它是 ListView 的升级版本支持更灵活的布局和功能。
我们创建一个RecyclerView的Adapter
public class MyRecyclerView extends RecyclerView.AdapterMyRecyclerView.MyHolder {private ListString strings;private Context context;public MyRecyclerView(ListString strings, Context context) {this.strings strings;this.context context;}NonNullOverridepublic MyRecyclerView.MyHolder onCreateViewHolder(NonNull ViewGroup parent, int viewType) {View view LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);MyRecyclerView.MyHolder viewHolder new MyHolder(view);Log.d(MyRecyclerView, onCreateViewHolder: );return viewHolder;}Overridepublic void onBindViewHolder(NonNull MyRecyclerView.MyHolder holder, int position) {holder.textView.setText(第 position 项);Log.d(MyRecyclerView, onBindViewHolder: position);}Overridepublic int getItemCount() {return strings null ? 0 : strings.size();}public class MyHolder extends RecyclerView.ViewHolder {private TextView textView;public MyHolder(NonNull View itemView) {super(itemView);textView itemView.findViewById(android.R.id.text1);}}
}
我们在onCreateViewHolder和onBindViewHolder都打印log。
onCreateViewHolder()会在创建一个新view的时候调用onBindViewHolder()会在已存在view绑定数据的时候调用。
我们来看一下运行时打印的log 在最开始加载view的时候两个方法onCreateViewHolder()和onBindViewHolder()都执行了但是当我们上下滑动RecyclerView的时候我们会发现只执行了onBindViewHolder()方法。所以说RecyclerView并不是会一直重新创建View而是会对view进行复用。
复用机制
当我们想去通过看源码去了解缓存复用机制的时候我们要去想看源码的入口在哪里。上文我们提到是在滑动RecyclerView的时候进行了缓存复用所以我们会想到去看 onTouchEvent 这个方法
Override
public boolean onTouchEvent(MotionEvent e) {...case MotionEvent.ACTION_MOVE: {final int index e.findPointerIndex(mScrollPointerId);if (index 0) {Log.e(TAG, Error processing scroll; pointer index for id mScrollPointerId not found. Did any MotionEvents get skipped?);return false;}final int x (int) (e.getX(index) 0.5f);final int y (int) (e.getY(index) 0.5f);int dx mLastTouchX - x;int dy mLastTouchY - y;if (mScrollState ! SCROLL_STATE_DRAGGING) {boolean startScroll false;if (canScrollHorizontally) {if (dx 0) {dx Math.max(0, dx - mTouchSlop);} else {dx Math.min(0, dx mTouchSlop);}if (dx ! 0) {startScroll true;}}if (canScrollVertically) {if (dy 0) {dy Math.max(0, dy - mTouchSlop);} else {dy Math.min(0, dy mTouchSlop);}if (dy ! 0) {startScroll true;}}if (startScroll) {setScrollState(SCROLL_STATE_DRAGGING);}}if (mScrollState SCROLL_STATE_DRAGGING) {mReusableIntPair[0] 0;mReusableIntPair[1] 0;if (dispatchNestedPreScroll(canScrollHorizontally ? dx : 0,canScrollVertically ? dy : 0,mReusableIntPair, mScrollOffset, TYPE_TOUCH)) {dx - mReusableIntPair[0];dy - mReusableIntPair[1];// Updated the nested offsetsmNestedOffsets[0] mScrollOffset[0];mNestedOffsets[1] mScrollOffset[1];// Scroll has initiated, prevent parents from interceptinggetParent().requestDisallowInterceptTouchEvent(true);}mLastTouchX x - mScrollOffset[0];mLastTouchY y - mScrollOffset[1];if (scrollByInternal(canScrollHorizontally ? dx : 0,canScrollVertically ? dy : 0,e)) {getParent().requestDisallowInterceptTouchEvent(true);}if (mGapWorker ! null (dx ! 0 || dy ! 0)) {mGapWorker.postFromTraversal(this, dx, dy);}}} break;...return true;
}在case:MotionEvent.ACTION_MOVE里有 scrollByInternal() 这个方法
boolean scrollByInternal(int x, int y, MotionEvent ev) {int unconsumedX 0;int unconsumedY 0;int consumedX 0;int consumedY 0;consumePendingUpdateOperations();if (mAdapter ! null) {mReusableIntPair[0] 0;mReusableIntPair[1] 0;scrollStep(x, y, mReusableIntPair);consumedX mReusableIntPair[0];consumedY mReusableIntPair[1];unconsumedX x - consumedX;unconsumedY y - consumedY;}if (!mItemDecorations.isEmpty()) {invalidate();}mReusableIntPair[0] 0;mReusableIntPair[1] 0;dispatchNestedScroll(consumedX, consumedY, unconsumedX, unconsumedY, mScrollOffset,TYPE_TOUCH, mReusableIntPair);unconsumedX - mReusableIntPair[0];unconsumedY - mReusableIntPair[1];boolean consumedNestedScroll mReusableIntPair[0] ! 0 || mReusableIntPair[1] ! 0;// Update the last touch co-ords, taking any scroll offset into accountmLastTouchX - mScrollOffset[0];mLastTouchY - mScrollOffset[1];mNestedOffsets[0] mScrollOffset[0];mNestedOffsets[1] mScrollOffset[1];if (getOverScrollMode() ! View.OVER_SCROLL_NEVER) {if (ev ! null !MotionEventCompat.isFromSource(ev, InputDevice.SOURCE_MOUSE)) {pullGlows(ev.getX(), unconsumedX, ev.getY(), unconsumedY);}considerReleasingGlowsOnScroll(x, y);}if (consumedX ! 0 || consumedY ! 0) {dispatchOnScrolled(consumedX, consumedY);}if (!awakenScrollBars()) {invalidate();}return consumedNestedScroll || consumedX ! 0 || consumedY ! 0;
}里面的 scrollStep() 方法
void scrollStep(int dx, int dy, Nullable int[] consumed) {startInterceptRequestLayout();onEnterLayoutOrScroll();TraceCompat.beginSection(TRACE_SCROLL_TAG);fillRemainingScrollValues(mState);int consumedX 0;int consumedY 0;if (dx ! 0) {consumedX mLayout.scrollHorizontallyBy(dx, mRecycler, mState);}if (dy ! 0) {consumedY mLayout.scrollVerticallyBy(dy, mRecycler, mState);}TraceCompat.endSection();repositionShadowingViews();onExitLayoutOrScroll();stopInterceptRequestLayout(false);if (consumed ! null) {consumed[0] consumedX;consumed[1] consumedY;}
}scrollHorizontallyBy 与 scrollVerticallyBy
Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,RecyclerView.State state) {if (mOrientation VERTICAL) {return 0;}return scrollBy(dx, recycler, state);
}
Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,RecyclerView.State state) {if (mOrientation HORIZONTAL) {return 0;}return scrollBy(dy, recycler, state);
}两个都执行的 scrollBy
int scrollBy(int delta, RecyclerView.Recycler recycler, RecyclerView.State state) {if (getChildCount() 0 || delta 0) {return 0;}ensureLayoutState();mLayoutState.mRecycle true;final int layoutDirection delta 0 ? LinearLayoutManager.LayoutState.LAYOUT_END : LinearLayoutManager.LayoutState.LAYOUT_START;final int absDelta Math.abs(delta);updateLayoutState(layoutDirection, absDelta, true, state);final int consumed mLayoutState.mScrollingOffset fill(recycler, mLayoutState, state, false);if (consumed 0) {if (DEBUG) {Log.d(TAG, Dont have any more elements to scroll);}return 0;}final int scrolled absDelta consumed ? layoutDirection * consumed : delta;mOrientationHelper.offsetChildren(-scrolled);if (DEBUG) {Log.d(TAG, scroll req: delta scrolled: scrolled);}mLayoutState.mLastScrollDelta scrolled;return scrolled;
}里面的 fill 方法最为关键
int fill(RecyclerView.Recycler recycler, LinearLayoutManager.LayoutState layoutState,RecyclerView.State state, boolean stopOnFocusable) {...while ((layoutState.mInfinite || remainingSpace 0) layoutState.hasMore(state)) {layoutChunkResult.resetInternal();if (RecyclerView.VERBOSE_TRACING) {TraceCompat.beginSection(LLM LayoutChunk);}layoutChunk(recycler, state, layoutState, layoutChunkResult);if (RecyclerView.VERBOSE_TRACING) {TraceCompat.endSection();}if (layoutChunkResult.mFinished) {break;}layoutState.mOffset layoutChunkResult.mConsumed * layoutState.mLayoutDirection;/*** Consume the available space if:* * layoutChunk did not request to be ignored* * OR we are laying out scrap children* * OR we are not doing pre-layout*/if (!layoutChunkResult.mIgnoreConsumed || layoutState.mScrapList ! null|| !state.isPreLayout()) {layoutState.mAvailable - layoutChunkResult.mConsumed;// we keep a separate remaining space because mAvailable is important for recyclingremainingSpace - layoutChunkResult.mConsumed;}if (layoutState.mScrollingOffset ! LinearLayoutManager.LayoutState.SCROLLING_OFFSET_NaN) {layoutState.mScrollingOffset layoutChunkResult.mConsumed;if (layoutState.mAvailable 0) {layoutState.mScrollingOffset layoutState.mAvailable;}recycleByLayoutState(recycler, layoutState);}if (stopOnFocusable layoutChunkResult.mFocusable) {break;}}if (DEBUG) {validateChildOrder();}return start - layoutState.mAvailable;
}这个方法功能是填充给定的布局通过while循环不断进行填充其中的 layoutChunk() 方法
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,LayoutState layoutState, LayoutChunkResult result) {View view layoutState.next(recycler);//获取下一项需要布局的视图if (view null) {if (DEBUG layoutState.mScrapList null) {throw new RuntimeException(received null view when unexpected);}// if we are laying out views in scrap, this may return null which means there is// no more items to layout.result.mFinished true;return;}RecyclerView.LayoutParams params (RecyclerView.LayoutParams) view.getLayoutParams();if (layoutState.mScrapList null) {if (mShouldReverseLayout (layoutState.mLayoutDirection LayoutState.LAYOUT_START)) {addView(view);//将视图添加到布局的末尾} else {addView(view, 0);//将视图添加到布局的开头}} else {if (mShouldReverseLayout (layoutState.mLayoutDirection LayoutState.LAYOUT_START)) {addDisappearingView(view);} else {addDisappearingView(view, 0);}}...
}依次点击 最后我们就找到了回收复用的最关键的代码。
ViewHolder tryGetViewHolderForPositionByDeadline(int position,boolean dryRun, long deadlineNs) {if (position 0 || position mState.getItemCount()) {throw new IndexOutOfBoundsException(Invalid item position position ( position ). Item count: mState.getItemCount() exceptionLabel());}boolean fromScrapOrHiddenOrCache false;ViewHolder holder null;// 0) If there is a changed scrap, try to find from thereif (mState.isPreLayout()) {holder getChangedScrapViewForPosition(position);fromScrapOrHiddenOrCache holder ! null;}// 1) Find by position from scrap/hidden list/cacheif (holder null) {holder getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);if (holder ! null) {if (!validateViewHolderForOffsetPosition(holder)) {// recycle holder (and unscrap if relevant) since it cant be usedif (!dryRun) {// we would like to recycle this but need to make sure it is not used by// animation logic etc.holder.addFlags(ViewHolder.FLAG_INVALID);if (holder.isScrap()) {removeDetachedView(holder.itemView, false);holder.unScrap();} else if (holder.wasReturnedFromScrap()) {holder.clearReturnedFromScrapFlag();}recycleViewHolderInternal(holder);}holder null;} else {fromScrapOrHiddenOrCache true;}}}if (holder null) {final int offsetPosition mAdapterHelper.findPositionOffset(position);if (offsetPosition 0 || offsetPosition mAdapter.getItemCount()) {throw new IndexOutOfBoundsException(Inconsistency detected. Invalid item position position (offset: offsetPosition ). state: mState.getItemCount() exceptionLabel());}final int type mAdapter.getItemViewType(offsetPosition);// 2) Find from scrap/cache via stable ids, if existsif (mAdapter.hasStableIds()) {holder getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),type, dryRun);if (holder ! null) {// update positionholder.mPosition offsetPosition;fromScrapOrHiddenOrCache true;}}if (holder null mViewCacheExtension ! null) {// We are NOT sending the offsetPosition because LayoutManager does not// know it.final View view mViewCacheExtension.getViewForPositionAndType(this, position, type);if (view ! null) {holder getChildViewHolder(view);if (holder null) {throw new IllegalArgumentException(getViewForPositionAndType returned a view which does not have a ViewHolder exceptionLabel());} else if (holder.shouldIgnore()) {throw new IllegalArgumentException(getViewForPositionAndType returned a view that is ignored. You must call stopIgnoring before returning this view. exceptionLabel());}}}if (holder null) { // fallback to poolif (DEBUG) {Log.d(TAG, tryGetViewHolderForPositionByDeadline( position ) fetching from shared pool);}holder getRecycledViewPool().getRecycledView(type);if (holder ! null) {holder.resetInternal();if (FORCE_INVALIDATE_DISPLAY_LIST) {invalidateDisplayListInt(holder);}}}if (holder null) {long start getNanoTime();if (deadlineNs ! FOREVER_NS !mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {// abort - we have a deadline we cant meetreturn null;}holder mAdapter.createViewHolder(RecyclerView.this, type);if (ALLOW_THREAD_GAP_WORK) {// only bother finding nested RV if prefetchingRecyclerView innerView findNestedRecyclerView(holder.itemView);if (innerView ! null) {holder.mNestedRecyclerView new WeakReference(innerView);}}long end getNanoTime();mRecyclerPool.factorInCreateTime(type, end - start);if (DEBUG) {Log.d(TAG, tryGetViewHolderForPositionByDeadline created new ViewHolder);}}}// This is very ugly but the only place we can grab this information// before the View is rebound and returned to the LayoutManager for post layout ops.// We dont need this in pre-layout since the VH is not updated by the LM.if (fromScrapOrHiddenOrCache !mState.isPreLayout() holder.hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST)) {holder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);if (mState.mRunSimpleAnimations) {int changeFlags ItemAnimator.buildAdapterChangeFlagsForAnimations(holder);changeFlags | ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;final ItemHolderInfo info mItemAnimator.recordPreLayoutInformation(mState,holder, changeFlags, holder.getUnmodifiedPayloads());recordAnimationInfoIfBouncedHiddenView(holder, info);}}boolean bound false;if (mState.isPreLayout() holder.isBound()) {// do not update unless we absolutely have to.holder.mPreLayoutPosition position;} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {if (DEBUG holder.isRemoved()) {throw new IllegalStateException(Removed holder should be bound and it should come here only in pre-layout. Holder: holder exceptionLabel());}final int offsetPosition mAdapterHelper.findPositionOffset(position);bound tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);}final ViewGroup.LayoutParams lp holder.itemView.getLayoutParams();final LayoutParams rvLayoutParams;if (lp null) {rvLayoutParams (LayoutParams) generateDefaultLayoutParams();holder.itemView.setLayoutParams(rvLayoutParams);} else if (!checkLayoutParams(lp)) {rvLayoutParams (LayoutParams) generateLayoutParams(lp);holder.itemView.setLayoutParams(rvLayoutParams);} else {rvLayoutParams (LayoutParams) lp;}rvLayoutParams.mViewHolder holder;rvLayoutParams.mPendingInvalidate fromScrapOrHiddenOrCache bound;return holder;
}从代码中我们可以看出复用的并不是一个个控件而是 ViewHolder(ItemView) 。
我们可以通过上面代码看出来RecyclerView的复用机制
第一层Changed Scrap
代码
if (mState.isPreLayout()) {holder getChangedScrapViewForPosition(position);fromScrapOrHiddenOrCache holder ! null;
}解释
如果当前处于预布局isPreLayout true会优先从变更缓存中获取。getChangedScrapViewForPosition(position)查找变更缓存mChangedScrap这里保存的是那些被标记为需要更新的ViewHolder。如果找到直接返回不需要从其他层中查找。 在 RecyclerView 的布局过程中预布局Pre-Layout 是 RecyclerView 为支持动画效果如插入、删除、移动等操作而执行的一个特殊布局阶段。 以下操作都会触发 预布局阶段并可能从变更缓存中获取视图来进行后续处理 插入、移除、范围更新notifyItemInserted, notifyItemRemoved, notifyItemRangeChanged 等视图的布局和数据绑定例如setAdapter, setHasStableIds布局管理器或动画的变化setLayoutManager, setItemAnimator视图的移动notifyItemMoved所有与动画相关的操作包括添加、删除、移动动画 第二层Scrap/Hidden/Cache
代码
if (holder null) {holder getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);if (holder ! null) {if (!validateViewHolderForOffsetPosition(holder)) {if (!dryRun) {holder.addFlags(ViewHolder.FLAG_INVALID);if (holder.isScrap()) {removeDetachedView(holder.itemView, false);holder.unScrap();} else if (holder.wasReturnedFromScrap()) {holder.clearReturnedFromScrapFlag();}recycleViewHolderInternal(holder);}holder null;} else {fromScrapOrHiddenOrCache true;}}
}解释 如果第一层缓存未命中尝试从 普通缓存层中获取包括 Scrap表示那些视图项暂时不可见但还可以复用的视图它们是最常见的一种缓存方式。被标记为废弃的视图在没有被回收之前可以复用。Hidden隐藏视图与 Scrap 类似但它们的存在通常是为了支持更复杂的布局切换、动画等。它们在显示区域外但仍然保留在缓存中直到需要重新显示。CacheRecyclerView 使用缓存来存储那些根据视图 ID 或类型等条件频繁访问的视图。它们通常在视图池中存储较长时间直到达到缓存容量限制。 调用 validateViewHolderForOffsetPosition(holder)检查缓存的有效性 如果无效比如位置错位将其回收。如果有效标记fromScrapOrHiddenOrCache true。
第三层Stable ID Cache
代码
if (holder null mAdapter.hasStableIds()) {holder getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);if (holder ! null) {holder.mPosition offsetPosition;fromScrapOrHiddenOrCache true;}
}解释
如果Adapter支持稳定IDhasStableIds true尝试通过稳定ID查找缓存中的ViewHolder。调用getScrapOrCachedViewForId通过ID获取匹配的ViewHolder。如果找到将其位置更新为offsetPosition并标记为来自缓存。 如何启用 Stable ID 为了使 RecyclerView 使用 Stable ID Cache必须确保以下两点 实现 hasStableIds() 方法 你需要在你的 RecyclerView.Adapter 中重写 hasStableIds() 方法并返回 true。这是启用 Stable ID Cache 的前提。返回稳定的 ID 在适配器的 getItemId() 方法中为每个项返回唯一的 ID。这个 ID 通常是数据中的唯一标识符比如数据库中的主键。 示例代码 public class MyAdapter extends RecyclerView.AdapterMyViewHolder {Overridepublic boolean hasStableIds() {return true; // 启用 Stable ID}Overridepublic long getItemId(int position) {// 假设你的数据项有一个唯一的 id 字段return myDataList.get(position).getId();}// 其他适配器方法...
}或者在构造方法中进行设置 public MyRecyclerViewAdapter(ListString strings, Context context) {this.strings strings;this.context context;setHasStableIds(true); // 启用稳定 ID
}第四层Recycled Pool
代码
if (holder null) {holder getRecycledViewPool().getRecycledView(type);if (holder ! null) {holder.resetInternal();}
}解释 Recycled Pool 是 RecyclerView 内部维护的一个缓存池用于存储已经被回收并不再使用的视图View。这些视图通常是已经滑出屏幕或者暂时不可见的视图。通过回收池RecyclerView 可以避免每次滚动时都重新创建视图而是将已回收的视图重新利用从而提升滚动性能。 回收池的工作机制是RecyclerView 会在视图不再需要时将它们放入回收池即已回收的视图池。当需要新的视图时RecyclerView 会从回收池中获取一个合适的视图进行重用。 回收池存储的是所有超出缓存数量限制的ViewHolder按type分类。 如果找到调用resetInternal()重置其状态。
最后一层创建新 ViewHolder
代码中涉及的部分
if (holder null) {holder mAdapter.createViewHolder(RecyclerView.this, type);
}说明
如果所有缓存机制都未找到匹配的 ViewHolder最终会调用 Adapter.createViewHolder 来创建新的实例。这是性能代价最高的一步。
我们通过点击 就可以找到我们每次写Adapter都用重写的 onCreateViewHolder方法了。
在后面的代码中我们依次点击 就可以找到我们每次写Adapter都用重写的 onBindViewHolder方法了。 已经到底啦 文章转载自: http://www.morning.rrxgx.cn.gov.cn.rrxgx.cn http://www.morning.tsqrc.cn.gov.cn.tsqrc.cn http://www.morning.yfddl.cn.gov.cn.yfddl.cn http://www.morning.dpsgq.cn.gov.cn.dpsgq.cn http://www.morning.gmnmh.cn.gov.cn.gmnmh.cn http://www.morning.lqlc.cn.gov.cn.lqlc.cn http://www.morning.lwyqd.cn.gov.cn.lwyqd.cn http://www.morning.c7630.cn.gov.cn.c7630.cn http://www.morning.zbkdm.cn.gov.cn.zbkdm.cn http://www.morning.gprzp.cn.gov.cn.gprzp.cn http://www.morning.ppwdh.cn.gov.cn.ppwdh.cn http://www.morning.twmp.cn.gov.cn.twmp.cn http://www.morning.yhwyh.cn.gov.cn.yhwyh.cn http://www.morning.pxspq.cn.gov.cn.pxspq.cn http://www.morning.qlpyn.cn.gov.cn.qlpyn.cn http://www.morning.jcxgr.cn.gov.cn.jcxgr.cn http://www.morning.yrhpg.cn.gov.cn.yrhpg.cn http://www.morning.xqqcq.cn.gov.cn.xqqcq.cn http://www.morning.nqbs.cn.gov.cn.nqbs.cn http://www.morning.btpzn.cn.gov.cn.btpzn.cn http://www.morning.qdrrh.cn.gov.cn.qdrrh.cn http://www.morning.lgqdl.cn.gov.cn.lgqdl.cn http://www.morning.wfbnp.cn.gov.cn.wfbnp.cn http://www.morning.kntsd.cn.gov.cn.kntsd.cn http://www.morning.seoqun.com.gov.cn.seoqun.com http://www.morning.xshkh.cn.gov.cn.xshkh.cn http://www.morning.qnbzs.cn.gov.cn.qnbzs.cn http://www.morning.msbct.cn.gov.cn.msbct.cn http://www.morning.bqfpm.cn.gov.cn.bqfpm.cn http://www.morning.dpfr.cn.gov.cn.dpfr.cn http://www.morning.zrpbf.cn.gov.cn.zrpbf.cn http://www.morning.rydbs.cn.gov.cn.rydbs.cn http://www.morning.hxftm.cn.gov.cn.hxftm.cn http://www.morning.rnmmh.cn.gov.cn.rnmmh.cn http://www.morning.yktwr.cn.gov.cn.yktwr.cn http://www.morning.kgltb.cn.gov.cn.kgltb.cn http://www.morning.rghkg.cn.gov.cn.rghkg.cn http://www.morning.rkqzx.cn.gov.cn.rkqzx.cn http://www.morning.rqqmd.cn.gov.cn.rqqmd.cn http://www.morning.bssjp.cn.gov.cn.bssjp.cn http://www.morning.xkyqq.cn.gov.cn.xkyqq.cn http://www.morning.tsgxz.cn.gov.cn.tsgxz.cn http://www.morning.clpkp.cn.gov.cn.clpkp.cn http://www.morning.lhhdy.cn.gov.cn.lhhdy.cn http://www.morning.mxdhy.cn.gov.cn.mxdhy.cn http://www.morning.gglhj.cn.gov.cn.gglhj.cn http://www.morning.rmjxp.cn.gov.cn.rmjxp.cn http://www.morning.cznsq.cn.gov.cn.cznsq.cn http://www.morning.smyxl.cn.gov.cn.smyxl.cn http://www.morning.zdgp.cn.gov.cn.zdgp.cn http://www.morning.yfrbn.cn.gov.cn.yfrbn.cn http://www.morning.xjwtq.cn.gov.cn.xjwtq.cn http://www.morning.rtkz.cn.gov.cn.rtkz.cn http://www.morning.qmnjn.cn.gov.cn.qmnjn.cn http://www.morning.bbtn.cn.gov.cn.bbtn.cn http://www.morning.gmwdl.cn.gov.cn.gmwdl.cn http://www.morning.mwrxz.cn.gov.cn.mwrxz.cn http://www.morning.rnqyy.cn.gov.cn.rnqyy.cn http://www.morning.skfkx.cn.gov.cn.skfkx.cn http://www.morning.fxzw.cn.gov.cn.fxzw.cn http://www.morning.ybhjs.cn.gov.cn.ybhjs.cn http://www.morning.gbsby.cn.gov.cn.gbsby.cn http://www.morning.lpcct.cn.gov.cn.lpcct.cn http://www.morning.rrcxs.cn.gov.cn.rrcxs.cn http://www.morning.qzpw.cn.gov.cn.qzpw.cn http://www.morning.tkchg.cn.gov.cn.tkchg.cn http://www.morning.mggwr.cn.gov.cn.mggwr.cn http://www.morning.huayaosteel.cn.gov.cn.huayaosteel.cn http://www.morning.djmdk.cn.gov.cn.djmdk.cn http://www.morning.gwqkk.cn.gov.cn.gwqkk.cn http://www.morning.yhwxn.cn.gov.cn.yhwxn.cn http://www.morning.kwwkm.cn.gov.cn.kwwkm.cn http://www.morning.wkws.cn.gov.cn.wkws.cn http://www.morning.thmlt.cn.gov.cn.thmlt.cn http://www.morning.qmzwl.cn.gov.cn.qmzwl.cn http://www.morning.ysbhj.cn.gov.cn.ysbhj.cn http://www.morning.hydkd.cn.gov.cn.hydkd.cn http://www.morning.gtjkh.cn.gov.cn.gtjkh.cn http://www.morning.5-73.com.gov.cn.5-73.com http://www.morning.pmnn.cn.gov.cn.pmnn.cn