ListView回收机制相关分析_listview 被回收了-程序员宅基地

技术标签: Android进阶  回收  listview  android  

原文地址:http://www.cnblogs.com/qiengo/p/3628235.html

  1. ListView结构关系

首先理清listview的层级关系,

使用Google Online Draw 画出继承关系图如下:

图中单独画出Scrollview是为了说明该ViewGroup并没有自带回收机制,如果要是Scrollview显示大量view,需要手动做处理。

重要的类有三个:Listview、AbsListView、AdapterView。各个类的大小如下:

  • Listview 3800
  • AbsListView 6920
  • AdapterView 1208

 

从Listview开始, ListView的初始化ListVIew.onLayout过程与普通视图的layout过程不同,流程图如下。从左向右,从上向下。

视图的创建过程的都会执行的三个步骤: onMeasure, onLayout, onDraw

图中可以看出重要的类有三个:Listview、AbsListView、AdapterView。主要的回收类RecycleBin位于AbsListView中。

  1. RecycleBin类解析

位于AbsListView中,6466-6900行。

AbsListView的源码中可以看到有个RecycleBin 对象mRecycler。(317行, The data set used to store unused views that should be reused during the next layout to avoid creating new ones. 用于存储不用的view,以便在下个layout中使用来避免创建新的。)注释说明:

The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the start of a layout. By construction, they are displaying current information. At the end of layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that could potentially be used by the adapter to avoid allocating views unnecessarily.

大意是使用两级view来进行回收:

ActiveView

激活view,当期显示在屏幕上的激活的view。

ScrapView

废弃view,被删除的ActiveView会被自动加入ScrapView。

然后看看RecycleBin内部的重要的的变量和方法:

2.1 RecycleBin变量
mRecyclerListener

当发生View回收时,mRecyclerListener若有注册,则会通知给注册者.RecyclerListener接口只有一个函数onMovedToScrapHeap,指明某个view被回收到了scrap heap. 该view不再被显示,任何相关的昂贵资源应该被丢弃。该函数是处理回收时view中的资源释放。

mFirstActivePosition

The position of the first view stored in mActiveViews.存储在mActiveViews中的第一个view的位置,即getFirstVisiblePosition

mActiveViews

: Views that were on screen at the start of layout. This array is populated at the start of layout, and at the end of layout all view in mActiveViews are moved to mScrapViews. Views in mActiveViews represent a contiguous range of Views, with position of the first view store in mFirstActivePosition.布局开始时屏幕显示的view,这个数组会在布局开始时填充,布局结束后所有view被移至mScrapViews。

mScrapViews

:ArrayList<View>[] Unsorted views that can be used by the adapter as a convert view.可以被适配器用作convert view的无序view数组。 这个ArrayList就是adapter中getView方法中的参数convertView的来源。注意:这里是一个数组,因为如果adapter中数据有多种类型,那么就会有多个ScrapViews

 

mViewTypeCount

:view类型总数,列表中可能有多种数据类型,比如内容数据和分割符。

mCurrentScrap

:跟mScrapViews的却别是,mScrapViews是个队列数组,ArrayList<View>[]类型,数组长度为mViewTypeCount,而默认ViewTypeCount = 1的情况下mCurrentScrap=mScrapViews[0]。

下面三个参数分别对应addScrapView中scrapHasTransientState的三个情况

  • mTransientStateViews: If the data hasn't changed, we can reuse the views at their old positions.
  • mTransientStateViewsById: If the adapter has stable IDs,we can reuse the view forthe same data.
  • mSkippedScrap:Otherwise, we'll have to remove the view and start over.
2.2 RecycleBin方法
markChildrenDirty

():为每个子类调用forceLayout()。mScrapView中回收回来的View设置一样标志,在下次被复用到ListView中时,告诉viewroot重新layoutviewforceLayout()方法只是设置标志,并不会通知其parent来重新layout

shouldRecycleViewType

():判断给定的viewviewType指明是否可以回收回。viewType < 0可以回收。指定忽略的( ITEM_VIEW_TYPE_IGNORE = -1),或者是 HeaderView /FootViewITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2)是不被回收的。如有特殊需要可以将自己定义的viewType设置为-1,否则,将会浪费内存,导致OOM

clear

() :Clears the scrap heap.清空废弃view堆,并将这些View从窗口中Detach

fillActiveViews

(int childCount, int firstActivePosition):Fill ActiveViews with all of the children of the AbsListView. childCount:The minimum number of views mActiveViews should hold. firstActivePosition:The position of the first view that will be stored in mActiveViews.用AbsListView.的所有子view填充ActiveViews,其中childCount是mActiveViews应该保存的最少的view数,firstActivePosition是mActiveViews中存储的首个view的位置。从代码看该方法的处理逻辑为将当前AbsListView的0-childCount个子类中的非header、footer类添加到mActiveViews数组中。Adapter中的数据个数未发生变化时,此时用户可能只是滚动,或点击等操作,ListViewitem的个数会发生变化,因此,需要将可视的item加入到mActiveView中来管理。

getActiveView

(int position):Get the view corresponding to the specified position. The view will be removed from mActiveViews if it is found. 获取mActiveViews中指定位置的view,如果找到会将该view从mActiveViews中移除。positionadapter中的绝对下标值,mFirstActivePosition前面说过了,是当前可视区域的下标值,对应在adapter中的绝对值,如果找到,则返回找到的View,并将mActiveView对应的位置设置为null

 

clearTransientStateViews()

Dump any currently saved views with transient state.清掉当前处于transient(转换)状态的所有保存的view。内部为mTransientStateViews和mTransientStateViewsById的clear()调用。

addScrapView

(View scrap, int position):将view放入scrapview list中。If the list data hasn't changed or the adapter has stable IDs, views with transient state will be preserved for later retrieval. scrap:要添加的view。Position:view在父类中的位置。放入时位置赋给scrappedFromPosition 有transient状态的view不会被scrap(废弃),会被加入mSkippedScrap。

就是将移出可视区域的view,设置它的scrappedFromPosition,然后从窗口中detachview,并根据viewType加入到mScrapView中。

该方法会调用mRecyclerListener 接口的函数onMovedToScrapHeap(6734)

if (mRecyclerListener != null) {

mRecyclerListener.onMovedToScrapHeap(scrap);

}

mRecyclerListener的设置可通过AbsListView的setRecyclerListener方法。

当view被回收准备再利用的时候设置要通知的监听器, 可以用来释放跟view有关的资源。这点似乎很有用。

public void setRecyclerListener(RecyclerListener listener) {

mRecycler.mRecyclerListener = listener;

}

 

 

getScrapView

(int position) :A view from the ScrapViews collection. These are unordered.该方法中调用了retrieveFromScrap(ArrayList<View> scrapViews, int position)。

retrieveFromScrap

(ArrayList<View> scrapViews, int position):无注释。(6902)该方法属于AbsListView。

int size = scrapViews.size();

if (size > 0) {

// See if we still have a view for this position.

for (int i=0; i<size; i++) {

View view = scrapViews.get(i);

if (((AbsListView.LayoutParams)view.getLayoutParams())

.scrappedFromPosition == position) {

scrapViews.remove(i);

return view;

}

}

return scrapViews.remove(size - 1);

else {

return null;

}

其中scrappedFromPosition :The position the view was removed from when pulled out of the scrap heap.(6412)根据position,从mScrapView中找:

    1. 如果有view.scrappedFromPosition = position的,直接返回该view

    2. 否则返回mScrapView中最后一个;

    3. 如果缓存中没有view,则返回null

        a. 第三种情况,这个最简单:

一开始,listview稳定后,显示N个,此时mScrapView中是没有缓存view的,当我们向上滚动一小段距离(第一个此时仍显示部分),新的view将会显示,此时listview会调用Adapter.getView,但是缓存中没有,因此convertViewnull,所以,我们得分配一块内存来创建新的convertView

        b. 第二种情况:

a中,我们继续向上滚动,直接第一个view完全移出屏幕(假设没有新的item),此时,第一个view就会被detach,并被加入到mScrapView中;然后,我们还继续向上滚动,直接后面又将要显示新的item view时,此时,系统会从mScrapView中找position对应的View,显然,是找不到的,则将从mScrapView中,取最后一个缓存的view传递给convertView

        c. 第一种情况:

紧接着在b中,第一个被完全移出,加入到mScrapView中,且没有新增的itemlistview中,此时,缓存中就只有第一个view;然后,我此时向下滑动,则之前的第一个item,将被显示出来,此时,从缓存中查找position对应的view有没有,当然,肯定是找到了,就直接返回了。

 

removeSkippedScrap()

Finish the removal of any views that skipped the scrap heap.清空mSkippedScrap。

scrapActiveViews

():Move all views remaining in mActiveViews to mScrapViews.将mActiveViews 中剩余的view放入mScrapViews。实际上就是将mActiveView中未使用的view回收(因为,此时已经移出可视区域了)。会调用mRecyclerListener.onMovedToScrapHeap(scrap);

pruneScrapViews

():确保mScrapViews 的数目不会超过mActiveViews的数目 (This can happen if an adapter does not recycle its views)。mScrapView中每个ScrapView数组大小不应该超过mActiveView的大小,如果超过,系统认为程序并没有复用convertView,而是每次都是创建一个新的view,为了避免产生大量的闲置内存且增加OOM的风险,系统会在每次回收后,去检查一下,将超过的部分释放掉,节约内存降低OOM风险。

reclaimScrapViews

(List<View> views):Puts all views in the scrap heap into the supplied list.mScrapView中所有的缓存view全部添加到指定的view list中,只看到有AbsListView.reclaimViews有调用到,但没有其它方法使用这个函数,可能在特殊情况下会使用到,但目前从framework中,看不出来。

setCacheColorHint

(int color):Updates the cache color hint of all known views.更新view的缓存颜色提示setDrawingCacheBackgroundColor。为所有的view绘置它们的背景色。

  1. RecycleBin的调用和关键方法

3.1 ListView
3.1.1 layoutChildren

1479-1729

    1583-当数据发生改变的时候,把当前的view放到scrapviews里面,否则标记为activeViews。

// Pull all children into the RecycleBin.

// These views will be reused if possible

final int firstPosition = mFirstPosition;

final RecycleBin recycleBin = mRecycler;

if (dataChanged) {

for (int i = 0; i < childCount; i++) {

recycleBin.addScrapView(getChildAt(i), firstPosition+i);

}

}else {

recycleBin.fillActiveViews(childCount, firstPosition);

}

// Clear out old views

detachAllViewsFromParent();

recycleBin.removeSkippedScrap();//移除所有old views

......

// Flush any cached views that did not get reused above

recycleBin.scrapActiveViews();//刷新缓存,将当前的ActiveVies 移动到 ScrapViews

dataChanged,从单词的意思我们就可以,这里的优化规则就是基于数据是否有变化,mDataChanged在makeAndAddView(见下文)中有使用。

step1:如果数据发生变化,就将所有view加入到mScrapView中,否则,将所有view放到mActiveView中;

step2:添加viewlistview中;

step3:回收mActiveView中的未使用的viewmScrapView中;

    注:在step1中,如果是addScrapView,则所有的view将会detach,如果是fillActiveViews,则不会detach,只有在step3中,未用到的view才会detach

 

3.1.2 makeAndAddView

(int position, int y, boolean flow, int childrenLeft,boolean selected)(1772)

Obtain the view and add it to our list of children. The view can be made fresh, converted from an unused view, or used as is if it was in the recycle bin.

View child;

if (!mDataChanged) { // 数据没有更新时,使用以前的view

// Try to use an existing view for this position

child = mRecycler.getActiveView(position);

if (child != null) {

// Found it -- we're using an existing child

// This just needs to be positioned

// 对复用的View针对当前需要进行配置。定位并且添加这个view到ViewGrop中的children列表,从回收站获取的视图不需要measure,所以最后一个参数为true

setupChild(child, position, y, flow, childrenLeft, selected, true);

return child;

}

}

// Make a new view for this position, or convert an unused view if possible

// 创建或者重用视图

child = obtainView(position, mIsScrap);

// This needs to be positioned and measured

setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);

return child;

 

3.1.3 setupChild

(View child, int position, int y, boolean flowDown, int childrenLeft, boolean selected, boolean recycled)(1812)

Add a view as a child and make sure it is measured (if necessary) and positioned properly.

 

3.1.4 setAdapter

(ListAdapter adapter) (457)

Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.

if (mAdapter != null && mDataSetObserver != null) {

mAdapter.unregisterDataSetObserver(mDataSetObserver);//移除了与当前listview的adapter绑定数据集观察者DataSetObserver

}

resetList();//重置listview,主要是清除所有的view,改变header、footer的状态

mRecycler.clear();//清除掉RecycleBin对象mRecycler中所有缓存的view,RecycleBin后面着重介绍,主要是关系到Listview中item的重用机制,它是AbsListview的一个内部类

if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { //判断是否有headerview和footview

mAdapter = new HeaderViewListAdapter(mHeaderViewInfosmFooterViewInfos, adapter);

else {

mAdapter = adapter;

}

mOldSelectedPosition = INVALID_POSITION;

mOldSelectedRowId = INVALID_ROW_ID;

// AbsListView#setAdapter will update choice mode states.

super.setAdapter(adapter);

 

if (mAdapter != null) {

mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();

mOldItemCount = mItemCount;

mItemCount = mAdapter.getCount();

checkFocus();

mDataSetObserver = new AdapterDataSetObserver();//注册headerview的观察者

mAdapter.registerDataSetObserver(mDataSetObserver);//在RecycleBin对象mRecycler记录下item类型的数量

mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

int position;

if (mStackFromBottom) {

position = lookForSelectablePosition(mItemCount - 1, false);

else {

position = lookForSelectablePosition(0, true);

}

setSelectedPositionInt(position);//AdapterView中的方法,记录当前的position

setNextSelectedPositionInt(position);//AdapterView中的方法,记录下一个position

if (mItemCount == 0) {

// Nothing selected

checkSelectionChanged();

}

else {

mAreAllItemsSelectable = true;

checkFocus();

// Nothing selected

checkSelectionChanged();

}

requestLayout();

 

 

3.1.5 scrollListItemsBy

(int amount)(3012-3082)

对子view滑动一定距离,添加view到底部或者移除顶部的不可见view。从注释看,不可见的item 的自动移除是在scrollListItemsBy中进行的。

 

private void scrollListItemsBy(int amount) {

offsetChildrenTopAndBottom(amount);

final int listBottom = getHeight() - mListPadding.bottom;//获取listview最底部位置

final int listTop = mListPadding.top; //获取listview最顶部位置

final AbsListView.RecycleBin recycleBin = mRecycler;

if (amount < 0) {

// shifted items up

// may need to pan views into the bottom space

int numChildren = getChildCount();

View last = getChildAt(numChildren - 1);

while (last.getBottom() < listBottom) { //最后的view高于底部时添加下一个view

final int lastVisiblePosition = mFirstPosition + numChildren - 1;

if (lastVisiblePosition < mItemCount - 1) {

last = addViewBelow(last, lastVisiblePosition);

numChildren++;

else {

break;

}

}

// may have brought in the last child of the list that is skinnier

// than the fading edge, thereby leaving space at the end. need

// to shift back

if (last.getBottom() < listBottom) { //到达最后一个view

offsetChildrenTopAndBottom(listBottom - last.getBottom());

}

// top views may be panned off screen

View first = getChildAt(0);

while (first.getBottom() < listTop) { //顶部view移除屏幕时

AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams();

if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {

recycleBin.addScrapView(first, mFirstPosition); //回收view

}

detachViewFromParent(first); //从父类中移除

first = getChildAt(0); //这行好像没用啊。。。。

mFirstPosition++;

}

else {

// shifted items down

View first = getChildAt(0);

// may need to pan views into top

while ((first.getTop() > listTop) && (mFirstPosition > 0)) { //顶部view上部有空间时添加view。

first = addViewAbove(first, mFirstPosition);

mFirstPosition--;

}

// may have brought the very first child of the list in too far and

// need to shift it back

if (first.getTop() > listTop) { //到达第一个view

offsetChildrenTopAndBottom(listTop - first.getTop());

}

int lastIndex = getChildCount() - 1;

View last = getChildAt(lastIndex);

// bottom view may be panned off screen

while (last.getTop() > listBottom) { //底部view移除屏幕的情况

AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams();

if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {

recycleBin.addScrapView(last, mFirstPosition+lastIndex);

}

detachViewFromParent(last);

last = getChildAt(--lastIndex);

}

}

}

 

从以上代码可以看出,Android中view回收的计算是其父view中不再显示的,如果scrollview中包含了一个wrap_content属性的listview,里面的内容并不会有任何回收,引起listview 的getheight函数获取的是一个足以显示所有内容的高度。

3.2 AbsListView
    
3.2.1 obtainView

(int position, boolean[] isScrap)(2227)

    Get a view and have it show the data associated with the specified position. 当这个方法被调用时,说明Recycle bin中的view已经不可用了,那么,现在唯一的方法就是,convert一个老的view,或者构造一个新的view。

position: 要显示的位置

isScrap: 是个boolean数组, 如果view从scrap heap获取,isScrap [0]为true,否则为false。

 

isScrap[0] = false;

View scrapView;

scrapView = mRecycler.getTransientStateView(position);

if (scrapView == null) {

// 查看回收站中是否有废弃无用的View,如果有,则使用它,无需New View。

scrapView = mRecycler.getScrapView(position);

}

View child;

if (scrapView != null) {  //此时说明可以从回收站中重新使用scrapView。

child = mAdapter.getView(position, scrapView, this);

if(child.getImportantForAccessibility()== IMPORTANT_FOR_ACCESSIBILITY_AUTO) {

child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);

}

if (child != scrapView) {

//如果重用的scrapView和adapter获得的view是不一样的,将scrapView进行回收  

mRecycler.addScrapView(scrapView, position);// scrapView 仍然放入回收站

if (mCacheColorHint != 0) {

child.setDrawingCacheBackgroundColor(mCacheColorHint);

}

else {

//如果重用的view和adapter获得的view是一样的,将isScrap[0]值为true,否则默认为false

isScrap[0] = true;

// Clear any system-managed transient state so that we can

// recycle this view and bind it to different data.

if (child.isAccessibilityFocused()) {

child.clearAccessibilityFocus();

}

child.dispatchFinishTemporaryDetach();

}

}else { //回收站中没有拿到数据,就只能够自己去inflate一个xml布局文件,或者new一个view

child =mAdapter.getView(position, nullthis); //当getview中传入的

converView=null的时候会在getView的方法中进行新建这个view  

if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {

child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);

}

if (mCacheColorHint != 0) {

child.setDrawingCacheBackgroundColor(mCacheColorHint);

}

}

 

    
3.2.2 trackMotionScroll

(int deltaY, int incrementalDeltaY)(4991)

监视滑动动作

deltaY: Amount to offset mMotionView. This is the accumulated delta since the motion began. 正数表示向下滑动。

incrementalDeltaY :Change in deltaY from the previous event.

.......

// 滚动时,不在可见范围内的item放入回收站。。。。。。。

if (down) {

int top = -incrementalDeltaY;

if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {

top += listPadding.top;

}

for (int i = 0; i < childCount; i++) {

final View child = getChildAt(i);

if (child.getBottom() >= top) {

break;

else {

count++;

int position = firstPosition + i;

if (position >= headerViewsCount && position < footerViewsStart) {

// The view will be rebound to new data, clear any

// system-managed transient state.

if (child.isAccessibilityFocused()) {

child.clearAccessibilityFocus();

}

mRecycler.addScrapView(child, position);//放入回收站

}

}

}

else {

int bottom = getHeight() - incrementalDeltaY;

if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {

bottom -= listPadding.bottom;

}

for (int i = childCount - 1; i >= 0; i--) {

final View child = getChildAt(i);

if (child.getTop() <= bottom) {

break;

else {

start = i;

count++;

int position = firstPosition + i;

if (position >= headerViewsCount && position < footerViewsStart) {

// The view will be rebound to new data, clear any

// system-managed transient state.

if (child.isAccessibilityFocused()) {

child.clearAccessibilityFocus();

}

mRecycler.addScrapView(child, position);//放入回收站

}

}

}

}

 

 

4. 用到的关键类

4.1 ViewType的使用

在listview中当有多种viewtype的时候,在adapter中继承设置getItemViewType方法可以更有效率 。示例如下:

.......

private static final int TYPE_ITEM = 0;

private static final int TYPE_SEPARATOR = 1;

private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;

 

@Override

public int getItemViewType(int position) {

return mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;

}

@Override

public int getViewTypeCount() {

return TYPE_MAX_COUNT;

}

 

@Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder = null;

int type = getItemViewType(position);

if (convertView == null) {

holder = new ViewHolder();

switch (type) {

case TYPE_ITEM:

convertView = mInflater.inflate(R.layout.item1, null);

holder.textView = (TextView)convertView.findViewById......;

break;

case TYPE_SEPARATOR:

convertView = mInflater.inflate(R.layout.item2, null);

holder.textView = (TextView)convertView.findViewById......;

break;

}

convertView.setTag(holder);

} else {

holder = (ViewHolder)convertView.getTag();

}

........

} 

 

 

 

 

 

 

 

如果实现了RecyclerListener接口,当一个View由于ListView的滑动被系统回收到RecycleBin的mScrapViews数组时,会调用RecyclerListener中的onMovedToScrapHeap(View view)方法。RecycleBin相当于一个临时存储不需要显示的那部分Views的对象,随着列表滑动,这些Views需要显示出来的时候,他们就被从RecycleBin中拿了出来,RecycleBin本身并不对mScrapViews中的对象做回收操作。

于是在工程里,为ListView添加RecyclerListener接口,并在onMovedToScrapHeap方法中释放ListItem包含的Bitmap资源,这样可以极大的减少内存占用。

 

 

4.2 TransientStateView

用来标记这个view的瞬时状态,用来告诉app无需关心其保存和恢复。从注释看,这种具有瞬时状态的view,用于在view动画播放等情况中。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chenxu6/article/details/47187749

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法