当前位置: 首页 > 编程日记 > 正文

横向ListView(一) ——开篇,基础逻辑实现

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

第一次写博文,写得不好的地方还望各位看客见谅

为了学习自定义软件开发,且定制出满足自己需求的控件(不需要将就地使用第三方源码),本人花了一周的时间开发了个横向ListView,写博客是为了记录整个开发过程及思路,也能和各位看客一起学习和探讨。

这一系列文章是针对的读者是已经了解listview缓存和工作原理的android开发人员,如果对listview缓存和工作原理还不了解的读者,可以查看以下文章:

《Android研究院之ListView原理学习与优化总结》

目前横向ListView的可替代方案有以下三种:

1.HorizontalScrollView——android官方提供

2.RecyclerView——android6.0提供的

3.第三方开源控件

尽管有众多的选择,但感觉还是自己会实现比较酷一些,还有就是,自己的东西可以随便改改改改改。

本篇文章将介绍横向ListView的实现基本思路,在接下来的一系列文章中将不断介绍整个控件的完善思路(包括:实现快速滚动、添加头/尾视图、添加滚动条、实现下拉刷新/上拉加载等)。

参考文章: 《Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现》


 横向ListView的基础逻辑:

1.新建java类,类名:HorizontalListView
 2.继承AdapterView
 3.实现setAdapter()和getAdapter()方法(需要为adapter注册数据观察器)
 4.实现onTouchEvent()方法响应事件(采用android提供的手势解析器GestureDetector解析事件)
 5.实现onLayout方法,布局列表项
     1).计算当前列表发生滚动的滚动“位移值”,记录已经发生有效滚动的“位移累加值”
     2).根据“位移值”提取需要缓存的视图(已经滚动到可视区域外的列表项)
     3).根据“位移值”设置需要显示的的列表项
     4).根据整体列表“显示偏移值”整顿所有列表项位置(调用子view的列表项)
     5).计算可以发生滚动的“最大位移值”

先上代码:

package com.hss.os.horizontallistview.history_version;

import android.content.Context;
import android.database.DataSetObserver;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 横向ListView的基础逻辑
 * 1.继承AdapterView
 * 2.实现setAdapter()和getAdapter()方法(需要为adapter注册数据观察器)
 * 3.实现onTouchEvent()方法响应事件(采用android提供的手势解析器GestureDetector解析事件)
 * 4.实现onLayout方法,布局列表项
     1).计算当前列表发生滚动的滚动“位移值”,记录已经发生有效滚动的“位移累加值”
     2).根据“位移值”提取需要缓存的视图(已经滚动到可视区域外的列表项)
     3).根据“位移值”设置需要显示的的列表项
     4).根据整体列表“显示偏移值”整顿所有列表项位置(调用子view的列表项)
     5).计算可以发生滚动的“最大位移值”
 *
 * Created by hss on 2017/7/17.
 */

public class HorizontalListView1 extends AdapterView<ListAdapter> {private ListAdapter adapter = null;
    private GestureDetector mGesture;
    private Queue<View> cacheView = new LinkedList<>();//列表项缓存视图
    private int firstItemIndex = 0;//显示的第一个子项的下标
    private int lastItemIndex = -1;//显示的最后的一个子项的下标
    private int scrollValue=0;//列表已经发生有效滚动的位移值
    private int hasToScrollValue=0;//接下来列表发生滚动所要达到的位移值
    private int maxScrollValue=Integer.MAX_VALUE;//列表发生滚动所能达到的最大位移值(这个由最后显示的列表项决定)
    private int displayOffset=0;//列表显示的偏移值(用于矫正列表显示的所有子项的显示位置)

    public HorizontalListView1(Context context) {super(context);
        init(context);
    }public HorizontalListView1(Context context, AttributeSet attrs) {super(context, attrs);
        init(context);
    }public HorizontalListView1(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
        init(context);
    }@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public HorizontalListView1(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }private void init(Context context){mGesture = new GestureDetector(getContext(), mOnGesture);
    }private void initParams(){removeAllViewsInLayout();
        if(adapter!=null&&lastItemIndex<adapter.getCount())hasToScrollValue=scrollValue;//保持显示位置不变
        else hasToScrollValue=0;//滚动到列表头
        scrollValue=0;//列表已经发生有效滚动的位移值
        firstItemIndex = 0;//显示的第一个子项的下标
        lastItemIndex = -1;//显示的最后的一个子项的下标
        maxScrollValue=Integer.MAX_VALUE;//列表发生滚动所能达到的最大位移值(这个由最后显示的列表项决定)
        displayOffset=0;//列表显示的偏移值(用于矫正列表显示的所有子项的显示位置)
        requestLayout();
    }private DataSetObserver mDataObserver = new DataSetObserver() {@Override
        public void onChanged() {//执行Adapter数据改变时的逻辑
            initParams();
        }@Override
        public void onInvalidated() {//执行Adapter数据失效时的逻辑
            initParams();
        }};

    @Override
    public ListAdapter getAdapter() {return adapter;
    }@Override
    public void setAdapter(ListAdapter adapter) {if(adapter!=null){adapter.registerDataSetObserver(mDataObserver);
        }if(this.adapter!=null){this.adapter.unregisterDataSetObserver(mDataObserver);
        }this.adapter=adapter;
        requestLayout();
    }@Override
    public View getSelectedView() {return null;
    }@Override
    public void setSelection(int position) {}@Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);
        /*
         1).计算当前列表发生滚动的滚动“位移值”,记录已经发生有效滚动的“位移累加值”
         2).根据“位移值”提取需要缓存的视图(已经滚动到可视区域外的列表项)
         3).根据“位移值”设置需要显示的的列表项
         4).根据整体列表“显示偏移值”整顿所有列表项位置(调用子view的列表项)
         5).计算可以发生滚动的“最大位移值”
         */
        int dx=calculateScrollValue();
        removeNonVisibleItems(dx);
        showListItem(dx);
        adjustItems();
        calculateMaxScrollValue();
    }/**
     * 计算这一次整体滚动偏移量
     * @return
     */
    private int calculateScrollValue(){int dx=0;
        hasToScrollValue=hasToScrollValue<0? 0:hasToScrollValue;
        hasToScrollValue=hasToScrollValue>maxScrollValue? maxScrollValue:hasToScrollValue;
        dx=hasToScrollValue-scrollValue;
        scrollValue=hasToScrollValue;

        return -dx;
    }/**
     * 计算最大滚动值
     */
    private void calculateMaxScrollValue(){if(adapter==null) return; 
        if(lastItemIndex==adapter.getCount()-1) {//已经显示了最后一项  if(getChildAt(getChildCount() - 1).getRight()>=getShowEndEdge()) {maxScrollValue = scrollValue + getChildAt(getChildCount() - 1).getRight() - getShowEndEdge();            }else{maxScrollValue = 0;  }}    }/**
     * 根据偏移量提取需要缓存视图
     * @param dx
     */
    private void removeNonVisibleItems(int dx) {if(getChildCount()>0) {//移除列表头
            View child = getChildAt(getChildCount());
            while (getChildCount()>0&&child != null && child.getRight() + dx <= 0) {displayOffset += child.getMeasuredWidth();
                cacheView.offer(child);
                removeViewInLayout(child);
                firstItemIndex++;
                child = getChildAt(0);
            }//移除列表尾
            child = getChildAt(getChildCount()-1);
            while (getChildCount()>0&&child != null && child.getLeft() + dx >= getShowEndEdge()) {cacheView.offer(child);
                removeViewInLayout(child);
                lastItemIndex--;
                child = getChildAt(getChildCount()-1);
            }}}/**
     * 根据偏移量显示新的列表项
     * @param dx
     */
    private void showListItem(int dx) {if(adapter==null)return;

        int firstItemEdge = getFirstItemLeftEdge()+dx;
        int lastItemEdge = getLastItemRightEdge()+dx;
        displayOffset+=dx;//计算偏移量
        //显示列表头视图
        while(firstItemEdge > getPaddingLeft() && firstItemIndex-1 >= 0) {firstItemIndex--;//往前显示一个列表项
            View child = adapter.getView(firstItemIndex, cacheView.poll(), this);
            addAndMeasureChild(child, 0);
            firstItemEdge -= child.getMeasuredWidth();
            displayOffset -= child.getMeasuredWidth();
        }//显示列表未视图
        while(lastItemEdge < getShowEndEdge() && lastItemIndex+1 < adapter.getCount()) {lastItemIndex++;//往后显示一个列表项
            View child = adapter.getView(lastItemIndex, cacheView.poll(), this);
            addAndMeasureChild(child, getChildCount());
            lastItemEdge += child.getMeasuredWidth();
        }}/**
     * 调整各个item的位置
     */
    private void adjustItems() {if(getChildCount() > 0){int left = displayOffset+getPaddingLeft();
            int endIndex = getChildCount()-1;

            for(int i=0;i<=endIndex;i++){View child = getChildAt(i);
                int childWidth = child.getMeasuredWidth();
                child.layout(left, getPaddingTop(), left + childWidth, child.getMeasuredHeight()+getPaddingTop());
                left += childWidth + child.getPaddingRight();
            }}}/**
     * 取得视图可见区域的右边界
     * @return
     */
    private int getShowEndEdge(){return getWidth()-getPaddingRight();
    }private int getFirstItemLeftEdge(){if(getChildCount()>0) {return getChildAt(0).getLeft();
        }else{return 0;
        }}private int getLastItemRightEdge(){if(getChildCount()>0) {return getChildAt(getChildCount()-1).getRight();
        }else{return 0;
        }}private void addAndMeasureChild(View child, int viewIndex) {LayoutParams params = child.getLayoutParams();
        params = params==null ? new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT):params;

        addViewInLayout(child, viewIndex, params, true);
        child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.UNSPECIFIED),
                MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.UNSPECIFIED));
    }/**
     * 在onTouchEvent处理事件,让子视图优先消费事件
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {return mGesture.onTouchEvent(event);
    }private GestureDetector.OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {@Override
        public boolean onDown(MotionEvent e) {return true;
        }@Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {synchronized(HorizontalListView1.this){hasToScrollValue += (int)distanceX;
            }requestLayout();
            return true;
        }};
}

以下是具体实现解析:

第1-3步是整体实现的准备工作,比较简单,这里就不做讲解

4.实现onTouchEvent()方法响应事件(采用android提供的手势解析器GestureDetector解析事件)

处理触摸事件的方法有三个(以下说法针对当前使用的GestureDetector实现):

1.dispatchTouchEvent() —— 如果在这里处理,子视图和当前视图可以同时响应事件

2.onInterceptTouchEvent() —— 如果在这里处理,子视图无法响应事件

3.onTouchEvent() —— 优先子视图响应事件

以上三个方法涉及到事件分发机制,如果对这方面不是很懂也想学习的,可参考以下文章:

《Android View 事件传递》

《《Android深入透析》之Android事件分发机制 》

在实现GestureDetector.OnGestureListener时,必需实现onDown()和onScroll()两个方法

onScroll()方法用于获取用户的滚动行为所产生的滚动值

onDown()方法必须实现且返回值必须是true,否则onScroll()方法无法执行,具体原因还未深究

5.实现onLayout方法,布局列表项
     1).计算当前列表发生滚动的滚动“位移值”,记录已经发生有效滚动的“位移累加值”

private int calculateScrollValue(){int dx=0;
    hasToScrollValue=hasToScrollValue<0? 0:hasToScrollValue;
    hasToScrollValue=hasToScrollValue>maxScrollValue? maxScrollValue:hasToScrollValue;
    dx=hasToScrollValue-scrollValue;
    scrollValue=hasToScrollValue;

    return -dx;
}

在这里采用了三个变量:

private int scrollValue=0;//列表已经发生有效滚动的位移值
      private int hasToScrollValue=0;//接下来列表发生滚动所要达到的位移值
      private int maxScrollValue=Integer.MAX_VALUE;//列表发生滚动所能达到的最大位移值(这个由最后显示的列表项决定)

在这个时候就有个问题,为什么要采用这三个变量而不是直接使用用户滚动行为所产生的偏移值(onScroll()方法中的distanceX);直接使用distanceX去计算也是可以实现我们所需要的功能的,不过这样处理起来,各部分的逻辑代码耦合度就会很高,无法切分出各个步骤,这个对于代码的维护工作带来很大的不便,代码的可读性也不好,逻辑也不够清晰,采用这三个变量能很好的解决以上问题(这个思路是借用别人的,具体是谁最初想到的,我也不清楚,不过挺佩服的)

2).根据“位移值”提取需要缓存的视图(已经滚动到可视区域外的列表项)

/**
 * 根据偏移量提取需要缓存视图
 * @param dx
 */
private void removeNonVisibleItems(int dx) {if(getChildCount()>0) {//移除列表头
        View child = getChildAt(getChildCount());
        while (getChildCount()>0&&child != null && child.getRight() + dx <= 0) {displayOffset += child.getMeasuredWidth();
            cacheView.offer(child);
            removeViewInLayout(child);
            firstItemIndex++;
            child = getChildAt(0);
        }//移除列表尾
        child = getChildAt(getChildCount()-1);
        while (getChildCount()>0&&child != null && child.getLeft() + dx >= getShowEndEdge()) {cacheView.offer(child);
            removeViewInLayout(child);
            lastItemIndex--;
            child = getChildAt(getChildCount()-1);
        }}
}

这一步是在列表发生滚动之后根据发生滚动的位移值dx计算滚动后第一个和最后一个列表项是否已经滚动到不可见的区域(注意:可见的区域宽度 =(控件的宽度 - 左padding - 右padding))
     3).根据“位移值”设置需要显示的的列表项

/**
 * 根据偏移量显示新的列表项
 * @param dx
 */
private void showListItem(int dx) {if(adapter==null)return;

    int firstItemEdge = getFirstItemLeftEdge()+dx;
    int lastItemEdge = getLastItemRightEdge()+dx;
    displayOffset+=dx;//计算偏移量
    //显示列表头视图
    while(firstItemEdge > getPaddingLeft() && firstItemIndex-1 >= 0) {firstItemIndex--;//往前显示一个列表项
        View child = adapter.getView(firstItemIndex, cacheView.poll(), this);
        addAndMeasureChild(child, 0);
        firstItemEdge -= child.getMeasuredWidth();
        displayOffset -= child.getMeasuredWidth();
    }//显示列表未视图
    while(lastItemEdge < getShowEndEdge() && lastItemIndex+1 < adapter.getCount()) {lastItemIndex++;//往后显示一个列表项
        View child = adapter.getView(lastItemIndex, cacheView.poll(), this);
        addAndMeasureChild(child, getChildCount());
        lastItemEdge += child.getMeasuredWidth();
    }
}

这一步根据列表滚动的“位移值dx”计算是否需要在列表中添加新的item View,如果列表在移动的过程中,第一个显示的item View的左边界出现在整体视图可见区域的左边界内即(firstItemEdge > getPaddingLeft() ),则在列表头添加一个新的item View,同时记录下整个列表显示的左边偏移值(displayOffset -= child.getMeasuredWidth(); ),该值十分重要,是体现整个列表显示状态的值;如果最后一个显示的item View的右边界出现在整体视图可见区域的右边界内即(lastItemEdge < getShowEndEdge() ) ,则在列表尾添加一个新的item View;第一次显示列表时,是以追加的方式显示item View的

注意:

1.代码中采用while() {}循环操作而不是采用if()直接判断是为了代码逻辑的严密性,实际上这里采用if()进行判断操作效果是一样的,可这样做整个代码的逻辑就不够严密,可能在以后的扩展中留下隐患(bug),在removeNonVisibleItems(int dx)方法中的while操作也是基于以上考虑

2.firstItemEdge 和lastItemEdge 的值采用以下方法计算,不仅是为了增强代码的可读性,更是为了往后的扩展做准备

private int getFirstItemLeftEdge(){if(getChildCount()>0) {return getChildAt(0).getLeft();
    }else{return 0;
    }
}private int getLastItemRightEdge(){if(getChildCount()>0) {return getChildAt(getChildCount()-1).getRight();
    }else{return 0;
    }
}


     4).根据整体列表“显示偏移值”整顿所有列表项位置(调用子view的列表项)

/**
 * 调整各个item的位置
 */
private void adjustItems() {if(getChildCount() > 0){int left = displayOffset+getPaddingLeft();
        int top = getPaddingTop();
        int endIndex = getChildCount()-1;

        int childWidth,childHeight;
        for(int i=0;i<=endIndex;i++){View child = getChildAt(i);
            childWidth = child.getMeasuredWidth();
            childHeight = child.getMeasuredHeight();
            child.layout(left, top, left + childWidth, top + childHeight);
            left += childWidth;
        }}
}

在这里是对视图项进行正确的布局排列,把各个列表项安放到合适的位置上;这个列表如何显示,总体依赖displayOffset这个值;值得注意的是,child.layout()中的right和bottom的值需要在宽和高的基础上分别加上left和top的值,否则整个item View无法完全显示。
     5).计算可以发生滚动的“最大位移值”

/**
 * 计算最大滚动值
 */
private void calculateMaxScrollValue(){if(adapter==null) return;

    if(lastItemIndex==adapter.getCount()-1) {//已经显示了最后一项
        if(getChildAt(getChildCount() - 1).getRight()>=getShowEndEdge()) {maxScrollValue = scrollValue + getChildAt(getChildCount() - 1).getRight() - getShowEndEdge();
        }else{maxScrollValue = 0;
        }}
}

当列表滚动到最后一个列表项时,则可计算整个列表可滚动最大值;scrollValue 表示已经发生滚动的距离getChildAt(getChildCount() - 1).getRight() - getShowEndEdge()表示还可以发生滚动的距离,也表示最后一个列表项(item View)未显示出来的部分;如果显示项过少而无法铺满整个控件,最大滚动位移值为0,即maxScrollValue = 0;

转载于:https://my.oschina.net/u/3614895/blog/1438912

相关文章:

HTTP Response中的Chunked编码

进行Chunked编码传输的HTTP Response会在消息头部设置&#xff1a; Transfer-Encoding: chunked 表示Content Body将用Chunked编码传输内容。 Chunked编码使用若干个Chunk串连而成&#xff0c;由一个标明长度为0的chunk标示结束。每个Chunk分为头部和正文两部分&#xff0c;头部…

ORACLE RAC 更改instance name完整步骤

下面是更改的部分步骤&#xff0c;但是启动问题还是存在&#xff0c;求达人完整。单实例的数据库修改SID比较简单&#xff0c;只需要修改pfile相关参数&#xff0c;就可以挂载数据库。 RAC环境其实一样&#xff0c;只不过除了修改pfile&#xff0c;还需要修改 OCR信息。首先来看…

炸裂!微软重磅推出混合现实平台 Mesh、基于 Excel 的低代码语言 Power Fx,Ignite 2021 太精彩!...

作者 | 伍杏玲出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;“一开始&#xff0c;这就是混合现实的梦想。” 在微软 Ignite 2021 大会上&#xff0c;微软 HoloLens 之父 Alex Kipman 头戴 HoloLens 2&#xff0c;出现在科技感十足的海底世界虚拟舞台上&#xff0…

Apache Spark 2.2.0 中文文档 翻译活动

为什么80%的码农都做不了架构师&#xff1f;>>> Spark 2.2.0 已然发布&#xff08;2017-07-11 发布&#xff09; 5 天了&#xff0c;更新了一些新套路吧&#xff01; 此版本从 Structured Streaming&#xff08;结构化流&#xff09;中删除 experimental&#xff0…

Unity3D常用代码总结

1 GUI汇总 function OnGUI() { GUI.Label(Rect(1,1,100,20),"Im a Label"); //1 GUI.Box(Rect(1,21,100,20),"Im a Box"); //2 GUI.Button(Rect(1,41,100,20),"Im a Button"); //3 GUI.RepeatButton(Rect(1,61,120,20),"Im a RepeatButton&…

Python 搭建车道智能检测系统

作者 | 李秋键责编 | 寇雪芹出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;引言&#xff1a;本文将利用opencv实现对复杂场景下车道线的实时检测&#xff1b;所使用的图像处理方法主要是在读取图片的基础上&#xff0c;进行多种边缘检测&#xff0c;然后对不同的检测…

ASP.NET弹出窗口技术之增加网站流量方法

作为Microsoft的最新建立动态Web网站的工具,ASP.NET相对于ASP和JSP在改变原始的Web编程方式方面有了长足的长进。它的代码与页面分离技术(CodeBehind)以及完善的Web服务器控件为程序员提供了一个更加符合传统编程的Web服务器端开发方式。但Web编程还是有着与传统编程不相同的特…

检查是否支持 SO_REUSEPORT

为什么80%的码农都做不了架构师&#xff1f;>>> int reuse_port(int sockfd) {#ifndef SO_REUSEPORT#define SO_REUSEPORT (15)#endifconst int on 1;return setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); } 转载于:https://my.oschina.n…

nginx的tmp文件过大导致磁盘空间不足一例

个人微博&#xff1a;http://weibo.com/h2fly欢迎技术交流现象&#xff1a;8月23之后&#xff0c;时不时收到服务器的/usrused > 90%的报警排查:1、du发现磁盘/usr使用不大&#xff0c;而报警使用的df》明显是有文件删除了空间没释放。注&#xff1a;du和df的实现机制不同&a…

10年Java老兵宝藏资料,吐血奉献!

2021都说工作不好找&#xff0c;也对开发人员的要求变高。前段时间自己有整理了一些Java后端开发面试常问的高频考点问题做成一份PDF文档&#xff08;1000道高频题&#xff09;&#xff0c;同时也整理一些图文解析及笔记&#xff0c;今天在这免费分享给大家&#xff0c;希望大家…

IOCP , kqueue , epoll ... 有多重要?

原文地址&#xff1a;http://blog.codingnow.com/2006/04/iocp_kqueue_epoll.html设计 mmo 服务器&#xff0c;我听过许多老生常谈&#xff0c;说起处理大量连接时&#xff0c; select 是多么低效。我们应该换用 iocp (windows), kqueue(freebsd), 或是 epoll(linux) 。的确&am…

[故障解决]图文:python启动报错:api-ms-win-crt-runtime-l1-1-0.dll丢失解决

python启动报错&#xff1a;api-ms-win-crt-runtime-l1-1-0.dll丢失解决 环境 Windows 7 SP1 x64python3.6.1报错 解决办法 1.下载VC redist&#xff08;安装时读条卡在&#xff1a;正在处理:Windows7_MSU_x64&#xff09;2.到C:\ProgramData\Package Cache\里面搜索&#xff0…

ASP.NET设计应用程序的七大绝招

随着微软.NET的流行&#xff0c;ASP.NET越来越为广大开发人员所接受。作为ASP.NET的开发人员&#xff0c;我们不仅需要掌握其基本的原理&#xff0c;更要多多实践&#xff0c;从实践中获取真正的开发本领。在我们的实际开发中&#xff0c;往往基本的原理满足不了开发需求&#…

Chromium之各国语言切换

在\src\build\Debug\locales\目录下存放着各国语言所需要的资源文件xx.pak,我这边共有53中语言支持。 命令行进入src\build\Debug目录,敲:chrome.exe --langzh-CN就能用中文简体,zh-CN可以根据需要换成各种语言版本。 Chrome的整个solution中&#xff0c;每种语言都会有个相应的…

程序员每天工作摸鱼俩小时,月薪35K?

职场上有很多奇奇怪怪的事。比如说有人爆肝996&#xff0c;工资却还养不活自己。有人每天工作摸鱼&#xff0c;但是却月薪数万。前端时间&#xff0c;小编在某职场社交平台上看到这么一则帖子#程序员摸鱼2小时月入35k#仔细看下&#xff0c;该员工每天的工作日常就是摸鱼的间隙工…

JAVA的get post 区别

1. get 是从服务器上获取数据&#xff0c;post 是向服务器传送数据。 get 请求返回 request - URI 所指出的任意信息。Post 请求用来发送电子邮件、新闻或发送能由交互用户填写的表格。这是唯一需要在请求中发送body的请求。使用Post请求时需要在报文首部 Content - Length 字段…

多些时间能少写些代码(转自酷壳 – CoolShell.cn)

我在我的微博上说过这样一段话&#xff0c;我想在这里把我的这个观点阐述地更完整一些。左耳朵耗子&#xff1a;聪明的程序员使用50%-70%的时间用来思考&#xff0c;尝试和权衡各种设计和实现&#xff0c;而用30% – 50%的时间是在忙碌着编码&#xff0c;调试和测试。聪明的老板…

HTTP协议之Chunked解析

在网上找了好一会&#xff0c;始终没发现有解析Chunked编码的文章&#xff0c;那就自己写一个吧&#xff0c;呵呵。网上使用Chunked编码的网站似乎并不是很多&#xff0c;除了那些使用GZip压缩的网站&#xff0c;例&#xff1a;google.com&#xff0c;还有就是大部分打开GZip压…

关于深度学习编译器,这些知识你需要知道

作者 | 小O妹出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;神经网络编译器概览近年来&#xff0c;以机器学习、深度学习为核心的AI技术得到迅猛发展&#xff0c;深度神经网络在各行各业得到广泛应用&#xff1a; 1. CV&#xff08;计算机视觉&#xff09;&#xf…

checkbox点击切换选中状态

2019独角兽企业重金招聘Python工程师标准>>> function cboxChecked(ele) {$(ele).click(function () {var isChecked $(ele).attr(checked);if (!isChecked) {$(ele).attr(checked, true)} else {$(ele).attr(checked, false)}})} 转载于:https://my.oschina.net/u…

提升Hadoop计算能力的并行框架

集算器是新型并行计算框架&#xff0c;它支持读写HDFS中的文件&#xff0c;可以通过并行框架将计算任务分担到多个节点中。它专注于加强Hadoop的计算能力&#xff0c;从而实现计算性能和开发效率更高的大数据应用。更强的计算能力。Hadoop所使用的计算语言为JAVA&#xff0c;JA…

在ASP.NET 2.0中建立站点导航层次

站点导航提供程序--ASP.NET 2.0中的站点导航提供程序暴露了应用程序中的页面的导航信息&#xff0c;它允许你单独地定义站点的结构&#xff0c;而不用考虑页面的实际物理布局。默认的站点导航提供程序是基于XML的&#xff0c;但是你也可以通过编写自定义的提供程序&#xff0c;…

加速数据中心变革,Xilinx推出软件定义、硬件加速型 Alveo SmartNIC

近日&#xff0c;为满足现代数据中心发展需求&#xff0c;赛灵思公司宣布推出一系列全新数据中心产品及解决方案&#xff0c;包括全新 Alveo SmartNIC 系列、smart world &#xff08;智能世界&#xff09; AI 视频分析应用、一款能够实现亚微秒级交易的加速算法交易参考设计&a…

跟阿里云技术专家阙寒一起深度了解视频直播CDN技术

网络直播平台现下已经十分火热&#xff0c;很多常见的直播平台都采用了阿里云直播CDN来搭建自身业务。今天&#xff0c;我们请来了阿里云CDN团队技术专家阙寒&#xff0c;来介绍下视频的一些基础知识和视频直播的架构。在进入正题之前&#xff0c;我们先来了解视频直播相关的名…

一个ASP.NET中使用的MessageBox类

/// <summary>/// 自定义信息对话框/// </summary>public class MessageBox{/// <summary>/// 定义一个web页面&#xff0c;用来显示用户自定错误提示信息/// </summary>System.Web.UI.Page p;/// <summary>/// 实例时&#xff0c;参数为:this 如…

Ubuntu 13.10 安装Terminalx 后更改默认终端设置

1、安装 terminalx&#xff0c; sudo apt-get install terminator 2、Ctrl Alt t 试一下打开什么终端&#xff0c;我的默认启动的是Terminator;如果想换换默认的终端&#xff0c;还需以下一步 3、接下来&#xff0c;安装dconf-tools&#xff0c;这个是设置默认终端的必须 打开…

360数科张家兴:如何突破三大瓶颈,破解金融科技发展难题?

3月6日&#xff0c;上海香港联会、普陀香港联会联合普陀新区联会&#xff0c;IFTA亚洲金融科技师学会共同举办了“沪港合作共创未来”——沪港两地金融科技线上论坛。本次活动通过沪港两地直播连线&#xff0c;探讨两地金融科技领域的发展机遇。麻省理工学院香港创坊执行董事冼…

通过改进算法来优化程序性能的真实案例(Ransac)

对于运行不了几次&#xff0c;一次运行不了多久的方法&#xff0c;我们不需要考虑性能优化&#xff0c;对于那些需要经常运行几百次几千次的方法&#xff0c;我们头脑里还是要有性能这根弦。C#太优雅方便了&#xff0c;以至于很多人写程序时根本就把性能抛到脑后了&#xff0c;…

ASP.NET中使用MD5和SHA1算法加密

你的主页或者你管理的网站有各种密码需要保护&#xff0c;把密码直接放在数据库或者文件中存在不少安全隐患&#xff0c;所以密码加密后存储是最常见的做法。在ASP.NET中实现加密非常容易。.NET SDK中提供了CookieAuthentication类&#xff0c;其中的HashPasswordForStoringInC…

不追逐标准化产品,360数科的一站式风控体系有何不同?

新冠肺炎疫情无疑加速了金融行业数字化转型&#xff0c;竞争者不断涌入&#xff0c;逐渐形成由BATJ、传统银行旗下金融科技子公司、以及专注于金融机构的数字化服务公司构成的竞争格局。然而&#xff0c;风控始终是金融行业的核心。作为定位于中国零售金融领域科技服务商的360数…