Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解

Blender点云渲染实战:用Geometry Nodes快速搞定论文配图(附Cycles渲染技巧) 本文详细介绍了如何利用Blender的Geometry Nodes系统,高效地将三维点云数据转化为高质量的科研论文配图。通过实战步骤,从数据导入、节点化几何处理、材质赋予到Cycles渲染引擎的优化设置,手把手教你制作出专业、美观的可视化图像,助力科研成果展示。 阅读详情
AI摘要

本文详细介绍Android中View的状态属性及如何根据这些状态切换背景图片。包括StateListDrawable的使用方法、View的状态值及其区别,以及如何在代码中实现背景图片的动态更新。

                                                

                                                                                                          本文原创,转载请注明出处:http://blog.youkuaiyun.com/qinjuning


      今天继续给大家分享下View的相关知识,重点有一下两点:


           1、View的几种不同状态属性

           2、如何根据不同状态去切换我们的背景图片。

 

 

开篇介绍:android背景选择器selector用法汇总


        对Android开发有经验的同学,对 <selector>节点的使用一定很熟悉,该节点的作用就是定义一组状态资源图片,使其能够

  在不同的状态下更换某个View的背景图片。例如,如下的hello_selection.xml文件定义:

<?xml version="1.0" encoding="utf-8" ?>   
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
  <!-- 触摸时并且当前窗口处于交互状态 -->  
  <item android:state_pressed="true" android:state_window_focused="true" android:drawable= "@drawable/pic1" />
  <!--  触摸时并且没有获得焦点状态 -->  
  <item android:state_pressed="true" android:state_focused="false" android:drawable="@drawable/pic2" />  
  <!--选中时的图片背景-->  
  <item android:state_selected="true" android:drawable="@drawable/pic3" />   
  <!--获得焦点时的图片背景-->  
  <item android:state_focused="true" android:drawable="@drawable/pic4" />  
  <!-- 窗口没有处于交互时的背景图片 -->  
  <item android:drawable="@drawable/pic5" /> 
</selector>

           更多关于 <selector>节点的使用请参考该博客<android背景选择器selector用法汇总>


       其实,前面说的xml文件,最终会被Android框架解析成StateListDrawable类对象。

 

 

知识点一:StateListDrawable类介绍


    类功能说明:该类定义了不同状态值下与之对应的图片资源,即我们可以利用该类保存多种状态值,多种图片资源。

    常用方法为:

       public void addState (int[] stateSet, Drawable drawable)

       功能: 给特定的状态集合设置drawable图片资源

       使用方式:参考前面的hello_selection.xml文件,我们利用代码去构建一个相同的StateListDrawable类对象,如下:

//初始化一个空对象
StateListDrawable stalistDrawable = new StateListDrawable();
//获取对应的属性值 Android框架自带的属性 attr
int pressed = android.R.attr.state_pressed;
int window_focused = android.R.attr.state_window_focused;
int focused = android.R.attr.state_focused;
int selected = android.R.attr.state_selected;

stalistDrawable.addState(new int []{pressed , window_focused}, getResources().getDrawable(R.drawable.pic1));
stalistDrawable.addState(new int []{pressed , -focused}, getResources().getDrawable(R.drawable.pic2);
stalistDrawable.addState(new int []{selected }, getResources().getDrawable(R.drawable.pic3);
stalistDrawable.addState(new int []{focused }, getResources().getDrawable(R.drawable.pic4);
//没有任何状态时显示的图片,我们给它设置我空集合
stalistDrawable.addState(new int []{}, getResources().getDrawable(R.drawable.pic5);

       

        上面的“-”负号表示对应的属性值为false

        当我们为某个View使用其作为背景色时,会根据状态进行背景图的转换。


      public boolean isStateful ()

     功能: 表明该状态改变了,对应的drawable图片是否会改变。

     注:在StateListDrawable类中,该方法返回为true,显然状态改变后,我们的图片会跟着改变。

 


知识点二:View的五种状态值

 

       一般来说,Android框架为View定义了四种不同的状态,这些状态值的改变会引发View相关操作,例如:更换背景图片、是否

   触发点击事件等;视

      视图几种不同状态含义见下图:

                             

     

   其中selected和focused的区别有如下几点:

      1,我们通过查看setSelected()方法,来获取相关信息。

        SDK中对setSelected()方法----对于与selected状态有如下说明:

             public void setSelected (boolean selected)

             Since: APILevel 1

             Changes the selection state of this view. Aview can be selected or not. Note that selection is not the same as

        focus. Views are typically selected in the context of an AdapterView like ListView or GridView ;the selected view is 

        the view that is highlighted.

            Parameters selected   true if the view must be selected, false otherwise


           由以上可知:selected不同于focus状态,通常在AdapterView类群下例如ListView或者GridView会使某个View处于

     selected状态,并且获得该状态的View处于高亮状态。

 

    2、一个窗口只能有一个视图获得焦点(focus),而一个窗口可以有多个视图处于”selected”状态中。

 

      总结:focused状态一般是由按键操作引起的;

                pressed状态是由触摸消息引起的;

                selected则完全是由应用程序主动调用setSelected()进行控制。

 

      例如:当我们触摸某个控件时,会导致pressed状态改变;获得焦点时,会导致focus状态变化。于是,我们可以通过这种

   更新后状态值去更新我们对应的Drawable对象了。

 


问题:如何根据状态值的改变去绘制/显示对应的背景图?


       当View任何状态值发生改变时,都会调用refreshDrawableList()方法去更新对应的背景Drawable对象。

       其整体调用流程如下: View.java类中

//路径:\frameworks\base\core\java\android\view\View.java
    /* Call this to force a view to update its drawable state. This will cause
     * drawableStateChanged to be called on this view. Views that are interested
     * in the new state should call getDrawableState.
     */ 
    //主要功能是根据当前的状态值去更换对应的背景Drawable对象
    public void refreshDrawableState() {
        mPrivateFlags |= DRAWABLE_STATE_DIRTY;
        //所有功能在这个函数里去完成
        drawableStateChanged();
        ...
    }
    /* This function is called whenever the state of the view changes in such
     * a way that it impacts the state of drawables being shown.
     */
    // 获得当前的状态属性--- 整型集合 ; 调用Drawable类的setState方法去获取资源。
    protected void drawableStateChanged() {
    	//该视图对应的Drawable对象,通常对应于StateListDrawable类对象
        Drawable d = mBGDrawable;   
        if (d != null && d.isStateful()) {  //通常都是成立的
        	//getDrawableState()方法主要功能:会根据当前View的状态属性值,将其转换为一个整型集合
        	//setState()方法主要功能:根据当前的获取到的状态,更新对应状态下的Drawable对象。
            d.setState(getDrawableState());
        }
    }
    /*Return an array of resource IDs of the drawable states representing the
     * current state of the view.
     */
    public final int[] getDrawableState() {
        if ((mDrawableState != null) && ((mPrivateFlags & DRAWABLE_STATE_DIRTY) == 0)) {
            return mDrawableState;
        } else {
        	//根据当前View的状态属性值,将其转换为一个整型集合,并返回
            mDrawableState = onCreateDrawableState(0);
            mPrivateFlags &= ~DRAWABLE_STATE_DIRTY;
            return mDrawableState;
        }
    }


       通过这段代码我们可以明白View内部是如何获取更细后的状态值以及动态获取对应的背景Drawable对象----setState()方法

去完成的。这儿我简单的分析下Drawable类里的setState()方法的功能,把流程给走一下:

    

         Step 1 、 setState()函数原型 ,

             函数位于:frameworks\base\graphics\java\android\graphics\drawable\StateListDrawable.java 类中


    //如果状态态值发生了改变,就回调onStateChange()方法。
    public boolean setState(final int[] stateSet) {
        if (!Arrays.equals(mStateSet, stateSet)) {
            mStateSet = stateSet;
            return onStateChange(stateSet);
        }
        return false;
    }

           该函数的主要功能: 判断状态值是否发生了变化,如果发生了变化,就调用onStateChange()方法进一步处理。

    

       Step 2 、onStateChange()函数原型:

            该函数位于 frameworks\base\graphics\java\android\graphics\drawable\StateListDrawable.java 类中


    //状态值发生了改变,我们需要找出第一个吻合的当前状态的Drawable对象
    protected boolean onStateChange(int[] stateSet) {
    	//要找出第一个吻合的当前状态的Drawable对象所在的索引位置, 具体匹配算法请自己深入源码看看
        int idx = mStateListState.indexOfStateSet(stateSet);
        ...
        //获取对应索引位置的Drawable对象
        if (selectDrawable(idx)) {
            return true;
        }
        ...
    }

          该函数的主要功能: 根据新的状态值,从StateListDrawable实例对象中,找到第一个完全吻合该新状态值的索引下标处 ;

   继而,调用selectDrawable()方法去获取索引下标的当前Drawable对象。

         具体查找算法在 mStateListState.indexOfStateSet(stateSet) 里实现了。基本思路是:查找第一个能完全吻合该新状态值

   的索引下标,如果找到了,则立即返回。 具体实现过程,只好看看源码咯。

  

       Step 3 、selectDrawable()函数原型:

            该函数位于 frameworks\base\graphics\java\android\graphics\drawable\StateListDrawable.java 类中

    public boolean selectDrawable(int idx)
    {
        if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
        	//获取对应索引位置的Drawable对象
            Drawable d = mDrawableContainerState.mDrawables[idx];
            ...
            mCurrDrawable = d; //mCurrDrawable即使当前Drawable对象
            mCurIndex = idx;
            ...
        } else {
           ...
        }
        //请求该View刷新自己,这个方法我们稍后讲解。
        invalidateSelf();
        return true;
    }

             该函数的主要功能是选择当前索引下标处的Drawable对象,并保存在mCurrDrawable中。



知识点三: 关于Drawable.Callback接口

   

    该接口定义了如下三个函数:     

    //该函数位于 frameworks\base\graphics\java\android\graphics\drawable\Drawable.java 类中
    public static interface Callback {
    	//如果Drawable对象的状态发生了变化,会请求View重新绘制,
    	//因此我们对应于该View的背景Drawable对象能够”绘制出来”.
        public void invalidateDrawable(Drawable who);
        //该函数目前还不懂
        public void scheduleDrawable(Drawable who, Runnable what, long when);
         //该函数目前还不懂
        public void unscheduleDrawable(Drawable who, Runnable what);
    }

其中比较重要的函数为:


      public voidinvalidateDrawable(Drawable who)

        函数功能:如果Drawable对象的状态发生了变化,会请求View重新绘制,因此我们对应于该View的背景Drawable对象

   能够重新”绘制“出来。


    Android框架View类继承了该接口,同时实现了这三个函数的默认处理方式,其中invalidateDrawable()方法如下:

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource 
{
	...
	//Invalidates the specified Drawable.
    //默认实现,重新绘制该视图本身
    public void invalidateDrawable(Drawable drawable) {
        if (verifyDrawable(drawable)) { //是否是同一个Drawable对象,通常为真
            final Rect dirty = drawable.getBounds();
            final int scrollX = mScrollX;
            final int scrollY = mScrollY;
            //重新请求绘制该View,即重新调用该View的draw()方法  ...
            invalidate(dirty.left + scrollX, dirty.top + scrollY,
                    dirty.right + scrollX, dirty.bottom + scrollY);
        }
    }
	...
}


   因此,我们的Drawable类对象必须将View设置为回调对象,否则,即使改变了状态,也不会显示对应的背景图。 如下:

            Drawable d  ;                // 图片资源                        

            d.setCallback(View v) ;  // 视图v的背景资源为 d 对象


 

知识点四:View绘制背景图片过程


      在前面的博客中《Android中View绘制流程以及invalidate()等相关方法分析》,我们知道了一个视图的背景绘制过程时在

  View类里的draw()方法里完成的,我们这儿在回顾下draw()的流程,同时重点讲解下绘制背景的操作。


//方法所在路径:frameworks\base\core\java\android\view\View.java
//draw()绘制过程
private void draw(Canvas canvas){  
//该方法会做如下事情  
  //1 、绘制该View的背景  
    //其中背景图片绘制过程如下:
	//是否透明, 视图通常是透明的 , 为true
	 if (!dirtyOpaque) {
	   //开始绘制视图的背景
       final Drawable background = mBGDrawable;
       if (background != null) {
           final int scrollX = mScrollX;  //获取偏移值
           final int scrollY = mScrollY;
           //视图的布局坐标是否发生了改变, 即是否重新layout了。
           if (mBackgroundSizeChanged) {
          	 //如果是,我们的Drawable对象需要重新设置大小了,即填充该View。
               background.setBounds(0, 0,  mRight - mLeft, mBottom - mTop);
               mBackgroundSizeChanged = false;
           }
           //View没有发生偏移
           if ((scrollX | scrollY) == 0) {
               background.draw(canvas); //OK, 该方法会绘制当前StateListDrawable的当前背景Drawable
           } else {
          	 //View发生偏移,由于背景图片值显示在布局坐标中,即背景图片不会发生偏移,只有视图内容onDraw()会发生偏移
          	 //我们调整canvas对象的绘制区域,绘制完成后对canvas对象属性调整回来
               canvas.translate(scrollX, scrollY);
               background.draw(canvas); //OK, 该方法会绘制当前StateListDrawable的当前背景Drawable
               canvas.translate(-scrollX, -scrollY);
           }
       }
   }
	...
 //2、为绘制渐变框做一些准备操作  
 //3、调用onDraw()方法绘制视图本身  
 //4、调用dispatchDraw()方法绘制每个子视图,dispatchDraw()已经在Android框架中实现了,在ViewGroup方法中。  
 //5、绘制渐变框    
}  


      That's all ! 我们用到的知识点也就这么多吧。 如果大家有丝丝不明白的话,可以去看下源代码,具体去分析下这些流程到底

  是怎么走下来的。

      我们从宏观的角度分析了View绘制不同状态背景的原理,View框架就是这么做的。为了易于理解性,

  下面我们通过一个小Demo来演示前面种种流程。

   

 Demo 说明:


          我们参照View框架中绘制不同背景图的实现原理,自定义一个View类,通过给它设定StateListDrawable对象,使其能够在

   不同状态时能动态"绘制"背景图片。 基本流程方法和View.java类实现过程一模一样。

    截图如下:


                      


                 初始背景图                                                            触摸后显示的背景图(pressed)


  一、主文件MainActivity.java如下:

/**
 * 
 * @author http://http://blog.youkuaiyun.com/qinjuning
 */
public class MainActivity extends Activity
{

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);    

        LinearLayout ll  =  new LinearLayout(MainActivity.this);
        CustomView customView = new CustomView(MainActivity.this); 
        //简单设置为 width 200px - height 100px吧 
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(200 , 100);
        customView.setLayoutParams(lp);
        //需要将该View设置为可点击/触摸状态,否则触摸该View没有效果。
        customView.setClickable(true);
        
        ll.addView(customView);
        setContentView(ll); 
    }
}

   功能很简单,为Activity设置了视图 。


二、 自定义View如下 , CustomView.java :

/** 
 * @author http://http://blog.youkuaiyun.com/qinjuning
 */
//自定义View
public class CustomView extends View   /*extends Button*/
{
    private static String TAG = "TackTextView";
    
    private Context mContext = null;
    private Drawable mBackground = null;
    private boolean mBGSizeChanged = true;;   //视图View布局(layout)大小是否发生变化
    
    public CustomView(Context context)
    {
        super(context);
        mContext = context;       
        initStateListDrawable(); // 初始化图片资源
    }

    // 初始化图片资源
    private void initStateListDrawable()
    {
        //有两种方式获取我们的StateListDrawable对象:
        // 获取方式一、手动构建一个StateListDrawable对象
        StateListDrawable statelistDrawable = new StateListDrawable();
        
        int pressed = android.R.attr.state_pressed;
        int windowfocused = android.R.attr.state_window_focused;
        int enabled = android.R.attr.state_enabled;
        int stateFoucesd = android.R.attr.state_focused;
        //匹配状态时,是一种优先包含的关系。
        // "-"号表示该状态值为false .即不匹配
        statelistDrawable.addState(new int[] { pressed, windowfocused }, 
        		mContext.getResources().getDrawable(R.drawable.btn_power_on_pressed));
        statelistDrawable.addState(new int[]{ -pressed, windowfocused }, 
        		mContext.getResources().getDrawable(R.drawable.btn_power_on_nor));    
               
        mBackground = statelistDrawable;
        
        //必须设置回调,当改变状态时,会回掉该View进行invalidate()刷新操作.
        mBackground.setCallback(this);       
        //取消默认的背景图片,因为我们设置了自己的背景图片了,否则可能造成背景图片重叠。
        this.setBackgroundDrawable(null);
        
        // 获取方式二、、使用XML获取StateListDrawable对象
        // mBackground = mContext.getResources().getDrawable(R.drawable.tv_background);
    }
    
    protected void drawableStateChanged()
    {
        Log.i(TAG, "drawableStateChanged");
        Drawable d = mBackground;
        if (d != null && d.isStateful())
        {
            d.setState(getDrawableState());
            Log.i(TAG, "drawableStateChanged  and is 111");
        }

       Log.i(TAG, "drawableStateChanged  and is 222");
       super.drawableStateChanged();
    }
    //验证图片是否相等 , 在invalidateDrawable()会调用此方法,我们需要重写该方法。
    protected boolean verifyDrawable(Drawable who)
    {
        return who == mBackground || super.verifyDrawable(who);
    }
    //draw()过程,绘制背景图片...
    public void draw(Canvas canvas)
    {
        Log.i(TAG, " draw -----");
        if (mBackground != null)
        {
            if(mBGSizeChanged)
            {
                //设置边界范围
                mBackground.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
                mBGSizeChanged = false ;
            }
            if ((getScrollX() | getScrollY()) == 0)  //是否偏移
            {
                mBackground.draw(canvas); //绘制当前状态对应的图片
            }
            else
            {
                canvas.translate(getScrollX(), getScrollY());
                mBackground.draw(canvas); //绘制当前状态对应的图片
                canvas.translate(-getScrollX(), -getScrollY());
            }
        }
        super.draw(canvas);
    }
    public void onDraw(Canvas canvas) {    
        ...
    }
}


   将该View设置的背景图片转换为节点xml,形式如下:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true" 
        android:state_window_focused="true" 
        android:drawable="@drawable/btn_power_on_pressed"></item>
  <item android:state_pressed="false" 
        android:state_window_focused="true"  
        android:drawable="@drawable/btn_power_on_nor"></item>    
      
</selector>

          基本上所有功能都在这儿显示出来了, 和我们前面说的一模一样吧。

          当然了,如果你想偷懒,大可用系统定义好的一套工具 , 即直接使用setBackgroundXXX()或者在设置对应的属性,但是,

     万变不离其宗,掌握了绘制原理,可以潇洒走江湖了。

     


        示例Demo下载地址: http://download.youkuaiyun.com/detail/qinjuning/4237298


        PS: 如果您觉得本文对您有用,请不忘顶一下 。 - - .





Akamai-3.0补环境逆向-DHL快递查询 那么我们的请求过程就是:1.请求首页的html文件,通过re或xpath,提取到这个url,拼接官网地址,得到这个js文件的地址。返回的_abck为0,表示环境正确,请求搜索接口返回200,说明返回的_abck正确,如果过程错误或环境补的有问题会返回403或428这两个状态码。那么,就是这个包返回的,而且这个包需要请求两次,第一次get请求,返回的这个-1的cookie,第二次请求,带上一个sensor_data的参数,进行post请求,最终返回这个0的cookie,代表你过了akamai这个盾。 阅读详情

相关推荐

手把手教你设计2bit反射型超表面:从单patch扫参到pin管配置全流程

本文提供了一份2bit反射型超表面设计的完整工程实践指南。从单贴片谐振器的参数化扫描与“270度法则”应用,到PIN二极管等效电路模型的获取与集成,再到利用参数化扫描高效仿真四种工作状态,手把手指导读者完成从单元设计到阵列布局、偏置线集成及加工考量的全流程,旨在帮助射频工程师将概念转化为可加工测试的实体模型。

java5的博客 1020

Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解...

本文原创,转载请注明出处:http://blog.youkuaiyun.com/qinjuning 今天继续给大家分享下View的相关知识,重点有一下两点: 1、View的几种不同状态属性 2、如何根据不同状态去切...

tansitongba 334

省三医院新门诊大楼网络安全建设项目实施方案

为了响应国家建设数字医疗,构建医联网、医共体的号召,新门诊大楼现有计算机网络,实现各门诊室、药房、医学影像科室及后勤科室的终端数据互通。在互联网出口以三层模式部署两台防火墙,作为连接公网的出口设备;出于等保合规和自身业务安全的考虑,现需要该网络上通过网络安全设备实现安全建设。公网出口防火墙,配置攻击防御策略,防御互联网上的病毒进入内网。公网出口防火墙配置攻击防御策略,防御外网对内网的入侵行为。服务器取得边界防火墙,配置攻击防御策略,入侵防御策略。公网出口防火墙配置入侵防御策略,防御外网对内网发起的D。

m0_63645854的博客 2013

透明背景View绘制Bitmap,背景变为黑色

Bitmap.Config.RGB_565导致透明背景变为黑色

WXYDX的博客 1489

logisim计组实验八 乘法器

原理:点这里 有问题欢迎留言哦~ 文章目录五位阵列乘法器电路图时间延迟分析六位补码阵列乘法器五位无符号乘法流水线原理图电路图原码一位乘法器原理图电路图补码一位乘法器 五位阵列乘法器 电路图 此处注意:全加器FA的cout端是进位端而非输出端 使用硬件控制比循环累加的速度快得多。 但是存在串行进位链 改进版: 时间延迟分析 T是计算相加数的一级门延迟 3n–>2n 性能差别在1.5倍 ...

treblez's blog 2万+

Dify社区版多工作空间功能解锁:源码修改与多租户架构解析

多租户架构是现代SaaS平台实现数据隔离与资源管理的核心技术,其核心原理是通过租户模型将用户、应用和数据在逻辑上隔离。在AI应用开发平台中,这种架构能有效支持多团队、多项目并行开发,确保不同业务线的数据安全与独立迭代。Dify作为开源AI应用构建平台,其底层已设计完善的多租户模型,但社区版默认限制了单用户单工作空间。本文通过精准修改两处关键代码——账户初始化逻辑与系统功能开关,释放了平台固有的多工作空间管理能力。该方案无需改动数据库结构,直接利用现有RBAC权限体系,实现了类似企业版的**多租户隔离**体验

weixin_27059669的博客 1058

如何在MapView上画一个透明的背景

<br />Android教程1: MapView (Google Map)上的透明面板(直线样式)在这个教程中,我们将会告诉他家怎样创建一个透明面板。我们将展示怎样在一个Google Map中使用透明面板,你可以使用相同的技巧应用到其他的view中。 <br />从这一点上来说,这就是我们今天将要开发的东西——只在Android MapView的底部显示单一按钮的透明面板。 <br /><br /> <br /><br />我们将假设你已经知道Android编程的基本点,只会提到这些“高级的”话题: <b

ghd2000的专栏 3229

Cursor集成Claude 4.6免费版:本地IDE合规调用指南

大语言模型编程助手(LLM Copilot)已成为现代开发标配,其核心能力依赖于上下文理解、代码推理与结构化输出等关键技术原理。Anthropic官方提供的Claude系列模型,尤其Claude 4.6,凭借200K超长上下文、tool use函数调用和严格可控的API设计,在工程实践中展现出显著技术价值。该能力可无缝嵌入本地IDE环境,支撑代码解释、跨文件分析、单元测试生成等高频开发场景。本文聚焦Cursor这一开源可审计IDE,详解如何合规复用Anthropic免费tier接口(/v1/messages

weixin_34095889的博客 537

Android view不同状态下切换不同背景

一般是通过设置background为drawable资源实现不同状态不同背景。 代码如下: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:stat...

孙先森的博客 1085

SpringBoot一次请求中缓存数据,请求结束就清除的4种方法,你会几种?

通过以上四种方法,你可以在 SpringBoot 的一次请求中缓存数据,并在请求结束后自动清除这些缓存数据。使用 ThreadLocal:适用于需要跨多个方法调用的缓存数据,灵活性高,但需要注意内存泄漏问题。使用 AOP:适用于全局性的缓存管理,代码更加优雅,但需要对 AOP 有一定的了解。使用 ServletRequestListener:适用于简单的请求生命周期管理,配置简单,但功能相对有限。使用 HttpServletRequest 的 setAttribute 和 getAttribute。

java专栏 1295

AI在电商中的搜索优化

自拟标题 《AI技术助力电商搜索优化:深度解析一线大厂面试题及算法编程实践》 概述 随着人工智能技术的不断发展,AI在电商搜索优化中的应用日益广泛。本文将围绕“AI在电商中的搜索优化”这一主题,介绍国内头部一线大厂如阿里巴巴、百度、腾讯、字节跳动等在面试中常见的AI相关面试题和算法编程题,并提供详尽的答案解

AI天才研究院 912

android 常见drawable状态的使用

项目中经常会用到自定义主题的功能,就很需要灵活的编写drawable来进行相应的配置。 选中效果图 未选中效果图 以下2中方式设置效果都是一样的 背景色更换:tab_left_bg.xml,选中是填充蓝色左边圆弧,未选中是蓝色描边的左边圆弧 颜色更换:tab_text_color_selector.xml (2)利用代码来自定义选中样式 2.关于coloe颜色的一些常用方法 color字符串转int color转成 R,G,B,A 十进制值 获取Color 的R,G,B,A 十六进制值 获取更深颜色

weixin_45407364的博客 607

【人工智能-数据集】RML2018 时域信号的时序信号和星座图的图片信号生成方式(可用于多模态特征融合)

RML2018(RadioML 2018)数据集是一个广泛用于无线通信信号识别的开源数据集。它包含了多种调制方式(如OOK、QPSK、16QAM等)在不同信噪比下的信号样本。这些数据以 HDF5 格式存储,适用于大规模的数据处理和分析。数据集特点:多调制方式:涵盖24种不同的调制方式。多信噪比:包括从-20 dB到30 dB的26种信噪比。大规模样本:每种调制方式和信噪比下包含4096个样本。数据切分:将原始的 HDF5 数据集按照调制方式和信噪比切分成单个文件,便于后续处理。样本选择。

若北辰 971

Android_View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解

本文原创,转载请注明出处:http://blog.youkuaiyun.com/qinjuning       今天继续给大家分享下View的相关知识,重点有一下两点:            1、View的几种不同状态属性            2、如何根据不同状态去切换我们的背景图片。     开篇介绍:android背景选择器selector

zimo2013的技术博客 2084

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

上一篇: Android中滑屏实现----手把手教你如何实现触摸滑屏以及Scroller类详解
下一篇: Android框架浅析之锁屏(Keyguard)机制原理
qinjuning
博客等级 码龄18年 5288粉丝 43原创
评论 26
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值