梦幻西游异常捕捉器(JDK动态代理遇到UndeclaredThrowableException异常排查)
梦幻西游异常捕捉器文章列表:
- 1、JDK动态代理遇到UndeclaredThrowableException异常排查
- 2、Python异常处理
- 3、不是吧?Fragment这么多API被废弃了,你还不知道?
- 4、銆?.Delphi璇硶鍩虹銆?.绋嬪簭寮傚父澶勭悊
- 5、红蜘蛛有哪些防治技巧?采取哪些方法、选用哪些药物防治最有效?
JDK动态代理遇到UndeclaredThrowableException异常排查
前言
上一篇文章我们聊了聊聊自定义SPI如何与sentinel整合实现熔断限流。在实现整合测试的过程,出现一个有趣的异常java.lang.reflect.UndeclaredThrowableException,当时在代码层做了一个全局异常捕获,示例如下
@RestControllerAdvicepublic class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public AjaxResult handleException(Exception e) { String msg = e.getMessage(); return AjaxResult.error(msg,500); } @ExceptionHandler(BlockException.class) public AjaxResult handleBlockException(BlockException e) { String msg = e.getMessage(); return AjaxResult.error(msg,429); }}
本来预期是触发限流时,就会捕获BlockException 异常,再封装一层渲染出去,没想到死活捕获不到BlockException 异常。
问题排查
通过debug发现,该问题是由于jdk动态代理引起,后面查找了一些资料,后面在官方的API文档查到这么一段话
他的大意大概是如果代理实例的调用处理程序的 invoke 方法抛出一个经过检查的异常(不可分配给 RuntimeException 或 Error 的 Throwable),且该异常不可分配给该方法的throws子局声明的任何异常类,则由代理实例上的方法调用抛出UndeclaredThrowableException异常。
这段话我们可以分析出如下场景
1、真实实例方法上没有声明异常,代理实例调用时抛出了受检异常
2、真实实例方法声明了非受检异常,代理实例调用时抛出了受检异常
解决方案
方案一:真实实例也声明受检异常
示例:
public class sqlserverDialect implements SqlDialect { @Override public String dialect() throws Exception{ return "sqlserver"; }
方案二:jdk动态代理的invoke进行捕获,同时可以自定义异常抛出
示例:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { CircuitBreakerInvocation invocation = new CircuitBreakerInvocation(target,method,args); try { return new CircuitBreakerInvoker().proceed(invocation); } catch (Throwable e) { throw new CircuitBreakerException(429,"too many request"); } }
方案三:捕获InvocationTargetException异常,并抛出真正的异常
为啥要InvocationTargetException,原因是因为我们自定义的异常是会被InvocationTargetException包裹
示例
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { CircuitBreakerInvocation invocation = new CircuitBreakerInvocation(target,method,args); try { return new CircuitBreakerInvoker().proceed(invocation); //用InvocationTargetException包裹是java.lang.reflect.UndeclaredThrowableException问题 } catch (InvocationTargetException e) { throw e.getTargetException(); } }
总结
如果是我们自己实现的组件,推荐直接使用方案三,即捕获InvocationTargetException异常。
如果是用第三方实现的组件,推荐方案一即在调用的实例方法声明异常,比如在使用springcloud alibaba sentinel熔断降级是有概率会出现UndeclaredThrowableException异常的,因为它也是基于动态代理,他抛出来的BlockException也是一个受检异常。示例如下
public class SqlServerDialect implements SqlDialect { @Override public String dialect() throws BlockException{ return "sqlserver"; }
如果使用第三方组件不想方案一,你也可以在第三方组件的基础上再加一层代理,或者对第三方组件进行切面拦截处理
demo链接
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-spi-enhance/springboot-spi-framework-circuitbreaker
Python异常处理
一、Python常见异常类型
总的来说,编写程序时遇到的错误可大致分为 2 类,分别为语法错误和运行时错误。在 Python 中,把这种运行时产生错误的情况叫做异常(Exceptions),常见的几种异常情况如下:
异常类型 | 含义 | 实例 |
AssertionError | 当assert关键字后的条件为假时,程序运行会停止并抛出AssertionError异常 | a=3 b=5 assert a b<5 |
AttributeError | 当试图访问的对象属性不存在时排除的异常 | age=18 age.len |
IndexError | 索引超过序列范围会引发此异常 | list_a=["python"] list_a[3] |
KeyError | 字典中查找一个不存在的关键字时引发此异常 | dict_a={"name":"张三"} dict_a["age"] |
NameError | 尝试访问一个未声明的变量时,引发此异常 | |
TypeError | 不同类型数据之间的无效操作 | 1 2 "hello" |
ZeroDivisionError | 除法运算中除数为0引发此异常 | a=1/0 |
详细异常指引:https://docs.python.org/3/library/exceptions.html#base-classes
1.Python语法错误
语法错误,即解析代码时出现的错误。当代码不符合 Python 语法规则时,Python解释器在解析时就会报出 SyntaxError 语法错误,与此同时还会明确指出最早探测到错误的语句。
示例:print "Hello,World!"
Python 3 已不再支持上面这种写法,所以在运行时,解释器会报语法错误。
2.Python运行时错误
运行时错误,即程序在语法上都是正确的,但在运行时发生了错误。
示例:a = 1/0
上面这句代码的意思是“用 1 除以 0,并赋值给 a 。因为 0 作除数是没有意义的,所以运行后会产生运行时错误。
在 Python 中,把这种运行时产生错误的情况叫做异常(Exceptions),常见的几种异常情况如下。
二、try except异常处理
当发生异常时,我们就需要对异常进行捕获,然后进行相应的处理。python的异常捕获常用try...except...结构,把可能发生错误的语句放在try模块里,用except来处理异常,每一个try,都必须至少对应一个except。 基本语法结构如下所示:
try:
...
except
...
1.不确定异常类型时
不确定异常类型时,可用万能异常捕获:Exception
# try...except...不确定异常类型时,可用万能异常捕获try: a = 1 b = 0 print(a / b)except Exception as e: # 不适用except异常捕获时,报错ZeroDivisionError: division by zero print(e) # division by zero print(e.args) # ('division by zero',)
2.指定异常类型
当确定异常类型时,可以指定异常类型,例如:FileNotFoundError
# try...except...指定异常类型try: f = open("a.txt") f.read()except FileNotFoundError as e: print(e) # [errno 2] No such file or directory: 'a.txt' print(e.args) # (2, 'No such file or directory') print(e.strerror) # No such file or directory print(e.filename) # a.txt print(e.errno) # 2
3.捕获多个异常
当可能存在多个异常时,既可以定义多个except来捕获多个异常,也可以在一个except中声明多个异常
# try...except...except...定义多个except捕获多个异常try: a = [1, 2] print(a[3])except IOError as e: # 由于try中的内容不属于IOError,所以会跳过这个异常,进入下一个异常进行判断 print("读写异常") print(e)except IndexError as e: print(f"数组越界异常:{e}") # 数组越界异常:list index out of range# try...except(IOError,ValueError)...一个except中声明多个异常try: a = [1, 2] print(a.index(3))except (IOError, ValueError) as e: print(f"读写异常或结果异常:{e}") # 读写异常或结果异常:3 is not in list
三、try except else详解
在原本的try except结构的基础上,Python 异常处理机制还提供了一个 else 块,也就是原有 try except 语句的基础上再添加一个 else 块,即try except else结构。 使用 else 包裹的代码,只有当 try 块没有捕获到任何异常时,才会得到执行;反之,如果 try 块捕获到异常,即调用对应的 except 来处理异常,else 块中的代码也不会得到执行。
# try...except...else...异常捕获try: age = 18 print(age)except ValueError as e: print(e)else: # 只有当try中定义的语句无异常时,才会走到else分支 print("无异常") # 打印结果:无异常
四、try except finally:资源回收
Python 异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作。在整个异常处理机制中,finally 语句的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其 中的代码块。
# try...except...finally...异常捕获try: f = open('read1.txt')except FileNotFoundError as e: print(e) # [Errno 2] No such file or directory: 'read1.txt'else: print("文件读写正常")finally: # 无论程序是否有异常,都会走到finally分支 print("over") # over
五、raise主动触发异常
当程序出现错误,Python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行。 raise 语句的基本语法格式为:
raise [exceptionName [(reason)]]
raise 语句有三种常用的用法:
raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在except块中),或默认引发RuntimeError 异常。
raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。
raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
# raise主动触发异常try: num = input("请输入一个数字:") if not num.isdigit(): raise ValueError('num 非数字,请输入数字')except ValueError as e: print("结果异常,请检查输入项")
六、traceback模块:获取异常信息
在实际调试程序的过程中,有时只获得异常的类型是远远不够的,还需要借助更详细的异常信息才能解决问题。捕获异常时,有 2 种方式可获得更多的异常信息,分别是:
◆ 使用 sys 模块中的 exc_info 方法;
◆ 使用 traceback 模块中的相关函数。
1.借助sys模块中的exc_info方法
try: f = open('read1.txt') f.read()except Exception as e: print(e) # [Errno 2] No such file or directory: 'read1.txt' print(sys.exc_info()) # 打印异常信息 # (<class 'FileNotFoundError'>, FileNotFoundError(2, 'No such file or directory'), <traceback object at 0x033F5048>)
2.使用traceback模块中的相关函数
使用 traceback 模块查看异常传播轨迹,首先需要将 traceback 模块引入,该模块提供了如下两个常用方法:
◆ traceback.print_exc():将异常传播轨迹信息输出到控制台或指定文件中。
◆ format_exc():返回一个字符串而不是打印到文件。
traceback.print_exc()
try: f = [0, 1, 2, 3] f.index(5)except ValueError as e: print(traceback.print_exc()) # 将异常信息输出到控制台或指定文件中,注:此时控制台打印的为捕获的异常信息,非报错
traceback.print_exc()打印的异常信息如下:
format_exc()
try: f = [0, 1, 2, 3] f.index(5)except ValueError as e: # print(traceback.print_exc()) # 将异常信息输出到控制台或指定文件中,注:此时控制台打印的为捕获的异常信息,非报错 error_info = traceback.format_exc() # 返回一个字符串而不是打印到文件 print(error_info)
总结
Python常见的异常类型分为语法错误和运行时错误,对于运行时错误,我们可以采用try except进行异常捕获,从而进行处理。不确定异常类型时,可用万能异常捕获:Exception,能够确定异常类型时,可以指定异常类型,例如:FileNotFoundError、IndexError......当可能存在多个异常时,既可以定义多个except来捕获多个异常,也可以在一个except中声明多个异常。
不是吧?Fragment这么多API被废弃了,你还不知道?
引言
Fragment 诞生之初就被定义为一个小型 Activity,因此它代理了 Activity 的许多能力(例如 startActivityForResult 等),职责不够单一。随着 Jetpack 各种新组件的出现,Fragment 的很多职责被有效地进行了分担,其本身也可以更好地聚焦在对 UI 的划分和管理上面,早设计的一些 API 也可以退出历史舞台了。本文就盘点一下 Fragment 那些被废弃的 API。
本文的介绍基于 Fragment 版本 1.4.0
一、instantiate
以前, Fragment 的构造函数不允许携带参数,因为某些场景中 Fragment 会由系统自动创建,例如基于 XML 创建 Fragment、Activity 被杀死后的恢复重建等等。此时,系统通过调用 instantiate 来创建 Fragment,instantiate 通过反射调用 Fragment 无参的构造函数。
现在 Fragment 的构造函数允许携带参数了,我们可以通过自定义 FragmentFactory,调用 Fragment 的任意构造函数,而系统通过调用 FragmentFactory 来创建 Fragment。
我们可以自定义 FragmentFactory,并重写它的 instantiate 方法来创建 Fragment:
class MyFragmentFactory(private val arg: Any) : FragmentFactory() { override fun instantiate(classLoader: ClassLoader, className: String): Fragment { val clazz = loadFragmentClass(classLoader, className) if (clazz == MyFragment::class.java) { return MyFragment(arg) } return super.instantiate(classLoader, className) }}
我们将 FragmentFactory 设置给 FragmentManger,之后系统就可以在各种场景中使用工厂创建 Fragment 了。
//Activityoverride fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = myFragmentFactory super.onCreate(savedInstanceState)}
注意 FragmentFactory 的设置必须在 super.onCreate 之前,因为当 Activity 进入重建路径时,会在 super.onCreate 中使用到它。
二、onActivityCreated
Fragment 早期设计中与 Activity 耦合较多,例如在生命周期方面上除了代理了 Activity 标准生命周期回调以外,还增加了 onActivityCreated 用来观察与 Activity 的绑定关系,onActivityCreated 被认为是 onStart 之前最后一个阶段,此时 Fragment 的 View Hierarchy 已经与 Activity 绑定,因此常用来在这里完成一些基于 View 的初始化工作。
现在,官方正在逐渐去掉 Fragment 与 Activity 之间的耦合,一个更加独立的 Fragment 更利于复用和测试,因此 onActivityCreated 被废除,取而代之的是在 onViewCreated 中处理与 View 相关的初始化逻辑,与 View 无关的初始化可以前置到 onCreate。但要注意 onViewCreated 回调的时间点,Fragment 的 View 还没加入 Activity View 的 Hierarchy。
如果我们实在需要获得 Activity 的 onCreate 事件通知,可以通过在 onAttach(Context) 中通过 LifecycleObserver 来获取。
override fun onAttach(context: Context) { super.onAttach(context) requireActivity().lifecycle.addObserver( object : DefaultLifecycleObserver { override fun onCreate(owner: LifecycleOwner) { owner.lifecycle.removeObserver(this) //... } })}
onAttach(Context) 是 API23 之后新增的 API,前身是 onAttach(Activity),它也是为了去掉与 Activity 的耦合而被废弃和取代。
三、setRetainInstance
当系统发生横竖屏旋转等 ConfigurationChanged 时,伴随 Activity 的重新 onCreate,Fragment 也会重新创建。setRetainInstance(true) 可以保持 ConfigurationChanged 之后的 Fragment 实例不变。因为有这个特性,以前我们经常会借助 setRetainInstance 来保存 Fragment 甚至 Activity 的状态。
但是使用 setRetainInstance 保存状态存在隐患,如果 Fragment 持有了对 Activity View 的引用则会造成泄露或者异常,所以我们仅保存与 View 无关的状态即可,不应该保存整个 Fragment 实例,所以 setRetainInstance/getRetainInstance 被废弃,取而代之的是推荐使用 ViewModel 保存状态。
对于 ViewModel 的基操想必大家都很熟悉就不赘述了。这里只提醒一点,既然 ViewModel 可以在 ConfigurationChanged 之后保持状态,那么 ViewModel 的初始化只需进行一次即可。不少人会像下面这样初始化 ViewModel。
class DetailTaskFragment : Fragment(R.layout.fragment_detailed_task){ private val viewModel : DetailTaskViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) //订阅 ViewModel viewMode.uiState.observe(viewLifecycleOwner) { //update ui } //请求数据 viewModel.fetchTaskData(requireArguments().getInt(TASK_ID)) }}
在 onViewCreated 中使用 fetchTaskData 请求数据,当横竖屏旋转造成 Fragment 重建时,虽然我们可以从 ViewModel 中获取最新数据,但是仍然会执行一次多余的 fetchTaskData 。因此更合理的 ViewModel 初始化时机应该是在其内部的 init 中进行,代码如下:
class TasksViewModel: ViewModel() { private val _tasks = MutableLiveData<List<Task>>() val tasks: LiveData<List<Task>> = _uiState init { viewModelScope.launch { _tasks.value = withContext(Dispatchers.IO){ TasksRepository.fetchTasks() } } }}
四、setUserVisibleHint
Fragment 经常配合 ViewPager 使用以满足多 Tab 页场景的需求。默认情况下屏幕外部的 Fragment 会跟随显示中的 Fragment 一同被加载,这会影响初始页面的显示速度。setUserVisibleHint 是以前我们常用的“懒加载”实现方案:当 ViewPager 中的 Fragment 进/出屏幕时,FragmentPagerAdapter 会对其调用 setUserVisibleHint,传入 true/false,通知其是否可见:
@Overridepublic void setUserVisibleHint(Boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { onVisible(); //自定义回调: 进入屏幕 } else { onInVisible();//离开屏幕 }}
如上,通过重写 setUserVisibleHint 我们可以在 onVisible/onInVisible 中获知 Fragment 显示的时机,便于实现懒加载。但是这种做法有缺陷,首先,你需要为 Fragment 增加基类来定义 onVisible/onInvisible,其次,新增的这两个方法跟原生的生命周期回调交织在一起,增加了代码复杂度和出错的概率。幸好现在我们有了新的“懒加载”解决方案:Fragmenttransaction#setMaxLifecycle:setMaxLifecycle 可以将屏幕外尚未显示的 Fragment 的最大的生命周期的状态限制在 Started。
当 Fragment 真正进入屏幕后再推进到 Resumed,此时 onResume 才会响应。借助 setMaxLifecycle 我们仅依靠原生回调即可实现懒加载,而且还避免了额外基类的引入。
如果你使用的是 ViewPager2,其对应的 FragmentStateAdapter 已经默认支持了 setMaxLifecycle 。对于传统的 ViewPager,启动 setMaxLifecycle 的方法也很简单,FragmentPagerAdapter 的构造方法新增了一个 behavior 参数, 只要在此处传值为 FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT 即可,在 instantiateItem 方法中,会根据 behavior 为创建的 Fragment 设置 setMaxLifecycle。
// FragmentPagerAdpater.java@Overridepublic Object instantiateItem(@NonNull ViewGroup container, int position) { ... if (fragment != mCurrentPrimaryItem) { fragment.setMenuVisibility(false); // mBehaviour为1的时候走新逻辑if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { // 初始化item时将其生命周期限制为STARTED mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED); } else { // 兼容旧版逻辑 fragment.setUserVisibleHint(false); } } return fragment;}
五、onActivityResult
以前,我们在 Fragment 可以通过 startActivityForResult/onActivityResult 启动 Activity 并获取返回的结果,这本质是调用了 Activity 的同名方法。随着 Activity Result API 的启用,startActivityForResult/onActivityResult 已经在 Activity 以及 Fragment 中被废弃。相对于 onActivityResult 的结果返回方式,Activity Result API 避免了对 RequestCode 的依赖,以更加直观的方式获得 Activity 返回结果。
基本使用步骤如下图:
首先,我们创建一个 ActivityResultContract,这里定义了跨 Activity 通信的输入输出协议,系统预置了一系列 ActivityResultContracts.XXXX 可直接使用。然后,我们使用 registerForActivityResult 注册我们的 Contract 和对应的 Callback,Callback 中我们可以获取 Activity 的返回结果。代码如下:
val launcher : ActivityResultLauncher = registerForActivityResult( //使用预置的 Contract:StartActivityForResult ActivityResultContracts.StartActivityForResult()) { activityResult -> // 获取 Activity 返回的 ActivityResult Log.d("TargetActivity", activityResult.toString()) // D/TargetActivity: ActivityResult{resultCode=RESULT_OK, data=Intent { (has extras) }} }
registerForActivityResult 会返回一个 ActivityResultLauncher 句柄,我们使用它启动 Activity,如下:
val intent = Intent(this, TargetActivity::class.java)launcher.launch(intent)
最后我们在目标 Activity 中调用 setResult 返回结果即可:
//TargetActivity.ktclass TargetActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setResult(Activity.RESULT_OK, Intent().putExtra("my-data", "data")) finish() }}
六、requestPermissions
requestPermissions/onRequestPermissionsResult 底层也是基于 startActivityForResult/onActivityResult 实现的,因此同样被废弃了,升级为 Result API 的方式。
ActivityResultContracts 预置了申请权限相关的 Contract:
request_permission.setOnClickListener { requestPermission.launch(permission.BLUETOOTH)}request_multiple_permission.setOnClickListener { requestMultiplePermissions.launch( arrayOf( permission.BLUETOOTH, permission.NFC, permission.ACCESS_FINE_LOCATION ) )}// 申请单一权限private val requestPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> // Do something if permission grantedif (isGranted) toast("Permission is granted") else toast("Permission is denied") }// 一次申请多权限private val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions : Map<String, Boolean> -> // Do something if some permissions granted or denied permissions.entries.forEach { // Do checking here } }
七、setTargetFragment
setTargetFragment/getTargetFragment 原本用于 Fragment 之间的通信,例如从 FragmentA 跳转到 FragmentB ,在 B 中发送结果返回给 A:
// 向 FragmentB 设置 targetFragmentFragmentB fragment = new FragmentB();fragment.setTargetFragment(FragmentA.this, AppConstant.REQ_CODE_SECOND_FRAGMENT);//切换至 FragmentBtransaction.replace(R.id.fragment_container, fragment).commit();// FragmentB 中获取 FragmentA 并进行回调Fragment fragment = getTargetFragment();fragment.onActivityResult(AppConstant.REQ_CODE_SECOND_FRAGMENT, Activity.RESULT_OK, inte
如上,代码非常简单,但是这样的通信无法感应生命周期,即使 FragmentA 处于后台也会在 onActivityResult 响应回调。目前 TargetFragment 相关 API 已经被废弃,取而代之的是更为合理的 Fragment Result API。
假设需要在 FragmentA 监听 FragmentB 返回的数据,首先在 FragmentA 设置监听。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setFragmentResultListener 是 fragment-ktx 提供的扩展函数 setFragmentResultListener("requestKey") { requestKey, bundle -> // 监听key为“requestKey”的结果, 并通过bundle获取 val result = bundle.getString("bundleKey") // ... }}// setFragmentResultListener 是Fragment的扩展函数,内部调用 FragmentManger 的同名方法public fun Fragment.setFragmentResultListener( requestKey: String, listener: ((requestKey: String, bundle: Bundle) -> Unit)) { parentFragmentManager.setFragmentResultListener(requestKey, this, listener)}
当从 FragmentB 返回结果时:
val result = "result"setFragmentResult("requestKey", bundleOf("bundleKey" to result))//setFragmentResult 也是 Fragment 的扩展函数,其内部调用 FragmentManger 的同名方法public fun Fragment.setFragmentResult(requestKey: String, result: Bundle) { parentFragmentManager.setFragmentResult(requestKey, result)}
上面的代码可以用下图表示:
FragmentA 通过 Key 向 FragmentManager 注册 ResultListener,FragmentB 返回 result 时, FM 通过 Key 将结果回调给FragmentA ,而且最重要的是 Result API 是生命周期可感知的,listener.onFragmentResult 在 Lifecycle.Event.ON_START 的时候才调用,也就是说只有当 FragmentA 返回到前台时,才会收到结果。
最后
Fragment 是帮助我们组织和管理 UI 的重要组件,即使在 Compose 时代也具有使用价值,因此谷歌官方一直致力于对它的 API 的优化,希望它更加易用和便于测试。这些已废弃的 API 在未来的版本中将会彻底删除,所以如果你还在使用着他们,应该尽快予以替换。
官方也提供了工具帮助我们发现对于过期 API 的使用,Fragment-1.4.0 之后,我们可以通过全局设置严格模式策略,发现项目中的问题:
class MyApplication : Application() { override fun onCreate() { super.onCreate() FragmentStrictMode.defaultPolicy = FragmentStrictMode.Policy.Builder() .detectFragmentTagUsage() //setTargetFragment的使用 .detectRetainInstanceUsage()//setRetainInstance的使用 .detectSetUserVisibleHint()//setUserVisibleHint的使用 .detectTargetFragmentUsage()//setTargetFragment的使用 .apply { if (BuildConfig.DEBUG) { // Debug 模式下崩溃 penaltyDeath() } else { // Release 模式下上报 penaltyListener { FirebaseCrashlytics.getInstance().recordException(it) } } } .build() }}
这里就还给大家分享一套完备的知识体系,整体参照了各家一线大厂高工岗位的招聘要求及岗位技能需求,并且每个具体的知识节点还附带有一整套体系化的学习资料、笔记进行辅助,帮助你把所学的知识点全部串联起来!
如果需要的话,可以顺手帮我点赞评论一下,直接私信我【笔记】免费领取
部分内容展示如下
01.Android必备底层技术:
Java序列化:Serializable原理、Parcelable接口原理、Json、XML
注解、泛型与反射:自定义注解、注解的使用、泛型擦除机制、泛型边界、Java方法与Arm指令、Method反射源码、invoke方法执行原理
虚拟机:JVM垃圾回收器机制、JVM内存分配策略、Android虚拟机与JVM底层区别、虚拟机底层Odex本地指令缓存机制、虚拟机如何分别加载class与object、虚拟机类加载模型
并发:Java线程本质讲解、线程原理、线程通信、UnSafe类、线程池
编译时技术:OOP面向切面之AspectJ、字节码手术刀JavaSSit实战、字节码插桩技术(ASM)实战
动态代理:动态代理实现原理、动态代理在虚拟机中运行时动态拼接Class字节码分析、ProxyGenerator生成字节码流程
高级数据结构与算法:HashMap源码、ArrayList源码、排序算法
Java IO:Java IO体系、IO文件操作
02.Framework:
Binder:Linux内存基础、Binder四层源码分析、Binder机制、Binder进程通信原理
Handler:Loop消息泵机制、Message解析
Zygote:init进程与Zygote进程、Zygote启动流程、Socket通信模式、APP启动过程
AMS:ActivityThread源码分析、AMS与ActivityThread通信原理、Activity启动机制
PMS:PMS源码、APK安装过程分析、PMS对安装包的解析原理
WMS:PhoneWindow实例化流程、DecorView创建过程、ViewRootImpl渲染机制
03.Android常用组件:
Activty:Activity管理栈与Activity的启动模式、Activity生命周期源码分析
Fragment:Fragment生命周期深入详解、Fragment事务管理机制详解、性能优化相关方案
Service:Service启动模式分析、Service管理与通信方案、Service生命周期底层详解
04.高级UI:
UI绘制原理:setContentView()方法下到底做了什么、AppCompatActivity与Activity的区别、UI测量、布局、绘制的底层执行流程
插件换肤:LayoutInflater加载布局分析、Android资源的加载机制、Resource与AssetManager
事件分发机制原理:事件执行U形链与L形链、事件拦截原理
属性动画:VSYNC刷新机制、ObjectAnimator与ValueAnimator源码讲解、Android属性动画:插值器与估值器
RecycleView:布局管理器LayoutManager详解、回收池设计思想、适配器模式原理
高阶贝塞尔曲线
05.Jetpack:
Lifecycle:Lifecycle源码、Lifecycle高阶应用
ViewModel:ViewModel源码、ViewModel应用技巧
LiveData:LiveData源码
Navigation:Navigation源码
Room:Room源码、Room LiveData监听数据库数据变更刷新页面原理
WorkManager内核
Pagging原理
DataBinding:单向绑定、双向绑定、如何与RecyclerView的配合使用、底层原理
06.性能优化:
启动优化:系统启动原理、Trace工具分析启动卡顿、类重排机制、资源文件重排机制
内存优化
UI渲染优化:UI层级规范及对UI加载的影响、UI卡顿原因及修复、UI绘制、布局、测量原因以及处理方案
卡顿优化:造成卡顿的原因分析、内存抖动与GC回收、回收算法
耗电优化
崩溃优化:项目崩溃异常捕获、优雅的异常处理方案、如何避免异常弹框
安全优化:APP加固实现(防反编译,dex加固)、https防抓包机制(数据传输加载,客户端服务器端双向加密校验)
网络优化:serializable原理、parcelable接口原理、http与https原理详解、protbuffer网络IO详解、gzip压缩方案
大图加载优化:Glide巨图加载机制原理分析、大图多级缓存实现方案
多线程并发优化
储存优化:Android文件系统-sdcard与内存存储、Shared Preference原理、MMAP内存映射
安装包优化:shrinkResources去除无用资源、合理设置多语言、webp实现图片瘦身、合理配置armable-v7的so库、Lint检查工具实践
如果需要的话,可以顺手帮我点赞评论一下,直接私信我【笔记】免费领取
07.音视频:
C/C :数据类型、数组、内存布局、指针、函数、预处理器、结构体、共用体、容器、类型转换、异常、文件流操作、线程
H.265/H.265:音视频格式封装原理、编码原理、视频流H264的组装原理切片NAL单元、视频流H264码流分析、切片与宏快,运动矢量、信源编码器、高频滤波、帧间拆分与帧内预测、CTU,PU TU编码结构、DSP芯片解码流程、MediaPlayer与DSP芯片交互机制、投屏架构、MediaProjection与MeidiaCodec交互机制、H265码流交换
MediaCodec:dsp芯片、编解码器的生命周期、解码器中输入队列与解析队列设计思想、MediaCodec中平缓解码解析、MediaExtractor 多路复用、MediaMuxer合成器、MediaFormat格式
音视频剪辑:视频剪辑、音频剪辑、音频合成、音谱显示、视频倒放
音视频直播:硬编码、软编码、native实现rtmp推流、摄像头预览帧编码NV21转YUV、视频画面封装拼接Packet包、音频流数据拼接Packet包、RtmpDump实时同步发送音视频数据、MediaProjection、Medicodec编码H264码流、rtmp推流
OpenGL与音视频解码:OpenGL绘制流程、矩阵、Opencv详解、人脸识别效果实现
OpenGL特效:CPU与GPU运行机制详解、世界坐标,布局坐标,与FBO坐标系、图像镜像与旋转处理、人脸定位与关键点定位、大眼效果、贴纸效果、美颜效果
FFmpeg万能播放器:FFmpeg结构体、声音播放原理、Surface的渲染、像素绘制原理与对齐机制、音视频同步原理、视频播放器整体架构
Webrtc音视频通话:WebRtc服务端环境搭建与Webrtc编译、1v1视频通话实现方案、群聊视频通话实现思路、多对多视频会议实现、1V1音视频通话实现
08.开源框架原理:
Okhttp
Retrofit
RxJava
Glide
Hilt
Dagger2
EventBus
组件化、插件化、热修复等
09.Gradle:
Groovy语法
Gradle Android插件配置
Gradle实践等
10.kotlin:
Kotlin语法
扩展使用
进阶使用
实践等
11.Flutter:
Dart语法
UI
进阶使用
优化
实践等
12.鸿蒙:
Ability组件
分布式任务
事件总线
鸿蒙线程
UI自定义控件等
如果需要的话,可以顺手帮我点赞评论一下,直接私信我【笔记】免费领取
Android路漫漫,共勉!
銆?.Delphi璇硶鍩虹銆?.绋嬪簭寮傚父澶勭悊
7.绋嬪簭寮傚父澶勭悊
Delphi瀵瑰簲鐢ㄧ▼搴忎腑浜х敓鐨勫紓甯稿畾涔夊湪SysUtils銆丏B銆丆omCtrl绛夊涓簱鍗曞厓涓€俓u003c/span>
7.1Object Pascal寮傚父鍩虹被
Delphi涓紝鎵€鏈夊紓甯哥殑鍩虹被鏄痋u003cspan class="candidate-entity-word" data-gid="5714485" qid="6579719299433256205" mention-index="0">Exception绫汇€傚叾涓昏灞炴€у拰鏂规硶濡備笅锛歕u003c/span>
1.灞炴€u003c/span>
HelpContext
HelpContext鏄疶helpContext绫荤殑瀹炰緥锛屾彁渚涗簡涓庡紓甯稿璞¤仈绯诲湪涓€璧风殑涓婁笅鏂囩浉鍏冲府鍔╀俊鎭殑搴忓垪鍙枫€傝搴忓垪鍙峰喅瀹氬綋鍙戠敓寮傚父鏃讹紝鐢ㄦ埛鎸塅1閿樉绀虹殑寮傚父閿欒鐨勫府鍔╀俊鎭€俓u003c/span>
Message
瀛樺偍寮傚父鍙戠敓鏃剁殑閿欒淇℃伅銆傚彲浠ラ€氳繃璇ュ睘鎬у湪鎻愮ず閿欒瀵硅瘽妗嗕腑鏄剧ず閿欒淇℃伅瀛楃涓层€俓u003c/span>
2.鏂规硶
Create(Const Msg: string)
璇ユ柟娉曠敤鏉ヤ骇鐢熶竴涓叿鏈夌畝鍗曟彁绀轰俊鎭殑瀵硅瘽妗嗭紝瀵硅瘽妗嗕腑鐨勬彁绀轰俊鎭敱Msg鎻愪緵銆俓u003c/span>
CreateFmt(Const Msg: string, Const Args: Array of Const)
璇ユ柟娉曠敤鏉ヤ骇鐢熶竴涓叿鏈夋牸寮忓寲瀛楃涓瞈u003c/span>鎻愮ず淇℃伅鐨勫璇濇锛屾牸寮忓寲瀛楃涓茬敱Msg鍜孿u003cspan class="candidate-entity-word" data-gid="2333223" qid="6665487093214483725" mention-index="1">Args鎻愪緵銆傚锛欳reateFmt('�u z %d..%d鑼冨洿鍐匼u0026#39;, [100, 0, 99])锛屼骇鐢熲€?00涓嶅湪0..99鑼冨洿鍐呪€溿€俓u003c/span>
CreateHelp(Const Msg: string, AhelpContext: integer)
璇ユ柟娉曚骇鐢熶竴涓叿鏈夌畝鍗曟彁绀轰俊鎭拰涓婁笅鏂囧府鍔╁簭鍒楀彿鐨勬彁绀哄璇濇锛屽叾涓細Msg鍙傛暟鏃舵樉绀哄湪寮傚父瀵硅瘽妗嗕腑鐨勬彁绀轰俊鎭紝AhelpContext鍙傛暟鏄紓甯搁敊璇俊鎭笂涓嬫枃甯姪搴忓垪鍙枫€俓u003c/span>
7.2Delphi鍐呭缓寮傚父绫籠u003c/h1>
Delphi鍐呭缓寮傚父绫诲緢澶氾紝涓嬮潰琛ㄦ牸鍒楀嚭甯歌鐨凞elphi鍐呭缓寮傚父绫伙細
寮傚父绫籠u003c/span> | 寮曞彂鏉′欢 |
EAbort | 绋嬪簭閬囧埌閿欒浣嗕笉寮瑰嚭瀵硅瘽妗哱u003c/span> |
EAccessViolation | 鏃犳晥鍐呭瓨璁块棶閿欒 |
EAssertionFailed | 鎵цAssert杩囩▼杩斿洖鍊兼槸False |
EControlC | 鍦ㄦ帶鍒跺彴涓紝鎸夈€怌trl銆?銆怌銆戠粍鍚堥敭閬囧埌閿欒 |
EConvertError | 鍦ㄥ瓧绗︿覆鎴栧叾浠栧璞¢泦杞崲鏃堕亣鍒伴敊璇痋u003c/span> |
EDivByZero | 鏁存暟闄ゆ暟鏄? |
EinOutError | 杈撳叆/杈撳嚭閿欒 |
EIntOverflow | 鏁存暟杩愮畻鏃讹紝缁撴灉瓒呰繃鍙橀噺瀹氫箟鑼冨洿 |
EMathError | 娴偣杩愮畻鍑虹幇閿欒 |
EOutOfMemory | 瓒呭嚭鍐呭瓨閿欒 |
EOverflow | 娴偣杩愮畻杩斿洖缁撴灉瓒呭嚭鍙橀噺瀹氫箟鑼冨洿 |
ErangeError | 鏁存暟鏁板€艰秴鍑哄彉閲忓畾涔夎寖鍥达紝渚嬪鏁扮粍涓嬫爣瓒婄晫 |
EStackOverflow | 鍫嗘爤婧㈠嚭閿欒 |
EWin32ErrorWindows | 閿欒 |
EzeroDivide | 娴偣杩愮畻闄ゆ暟鏄? |
EdatabaseError | 鏁版嵁搴撻敊璇紝鍦ㄦ暟鎹簱涓畾涔塡u003c/span> |
EupdateError | 鏁版嵁闆嗘彁渚涜€呴敊璇紝鍦ㄦ暟鎹簱涓畾涔塡u003c/span> |
EADOError | ADO鏁版嵁搴撻敊璇紝鍦╝dodb搴撲腑瀹氫箟 |
EDBEngineError | 鍑虹幇BDE閿欒锛屽湪dbtables搴撲腑瀹氫箟 |
EnoResultSet | 娌℃湁鎴愬姛鎵撳紑涓€涓暟鎹泦鏌ヨ |
7.3鑷畾涔夊紓甯哥被
铏界劧Delphi宸茬粡鏈夊緢澶氬唴寤虹殑寮傚父绫伙紝浣嗘湁鏃舵弧瓒充笉浜嗗簲鐢ㄩ渶姹傦紝姝ゆ椂锛屽彲浠ヨ嚜琛屽畾涔夊紓甯哥被锛岃嚜瀹氫箟寮傚父绫诲繀椤荤户鎵垮唴寤哄紓甯哥被銆備互涓嬩妇渚嬭鏄庢牎楠屽勾榫勬暟鎹殑姝g‘鎬э紝骞撮緞闄愬埗鍦?~99涔嬮棿銆俓u003c/span>
杩愯鏃剁晫闈㈠涓嬪浘鎵€绀猴細
浠g爜濡備笅锛歕u003c/span>
implementation{$R *.dfm}type VerifyAgeError = class(Exception) // 鑷畾涔夊紓甯哥被 function toAge(age: integer): integer; end;function VerifyAgeError.toAge(age: integer): integer;begin if (age >= 100) or (age < 0) then showmessage('骞撮緞涓嶇鍚堝疄闄咃紒'); result := abs(age) mod 99;end;// 鏍¢獙鎸夐挳浜嬩欢澶勭悊procedure TForm1.Button1Click(Sender: TObject);var a: integer;begin try a := strtoint(Edit1.Text); if (a >= 100) or (a < 0) then raise VerifyAgeError.Create('骞撮緞閿欒'); messagedlg('OK', mtinformation, [mbok], 0); except on e: EConvertError do messagedlg(e.Message, mterror, [mbok], 0); on e: VerifyAgeError do begin messagedlg(e.Message, mterror, [mbok], 0); Edit1.Text := inttostr(e.toAge(strtoint(Edit1.Text))); end; end;end;// 閫€鍑烘寜閽簨浠跺鐞哱nprocedure TForm1.Button2Click(Sender: TObject);begin close;end;end.
7.4瑙﹀彂寮傚父
寮傚父瑙﹀彂鍙互鍒嗕负涓ょ锛氫竴绉嶆槸绋嬪簭绯荤粺鑷姩瑙﹀彂锛屽彟涓€绉嶆槸鎵цraise鎸囦护瑙﹀彂銆傚涓婇潰鐨勪唬鐮佷腑锛孍ConvertError寮傚父灏辨槸鐢辩郴缁熷湪鎵ц瀛楃涓茶浆鎹㈡暣鍨嬫暟鍊肩殑鏃跺€欒嚜鍔ㄨЕ鍙戠殑锛岃€孷erifyAgeError鏄綋骞撮緞涓嶅湪鎸囧畾鑼冨洿鍐呮椂閫氳繃raise鎸囦护鎵嬪姩瑙﹀彂鐨勩€俓u003c/span>
raise鎸囦护鐨勮娉曟牸寮忥細
raise 寮傚父瀵硅薄
鍐嶆涓句緥璇存槑锛屼互涓嬩緥瀛愰€氳繃杈撳叆涓ゆ瀵嗙爜鐩稿悓鎴栦笉鍚岀殑鎯呭喌杩涜澶勭悊銆俓u003c/span>
杩愯鏃剁晫闈㈠涓嬪浘鎵€绀猴細
浠g爜濡備笅锛歕u003c/span>
implementation{$R *.dfm}type EPasswordInvalid = class(Exception);procedure TForm1.Button1Click(Sender: TObject);begin if edit1.Text <> edit2.Text then raise EPasswordInvalid.Create('瀵嗙爜杈撳叆鏈夎!') else begin showmessage('瀵嗙爜璁剧疆瀹屾垚锛乗u0026#39;); end; showmessage('娆㈣繋鍏変复锛乗u0026#39;);end;end.
7.5寮傚父鎹曡幏
鍦∣bject Pascal绋嬪簭璇█涓紝鏈変袱绉嶇敤鏉ュ鐞嗗紓甯哥殑璇彞锛歕u003c/span>
try...finally...end
try...except...end
1.try...finally...end
璇硶鏍煎紡锛歕u003c/span>
try <琚繚鎶よ鍙u0026gt;finally <寮傚父澶勭悊璇彞> //鏃犺寮傚父鍙戠敓鍚︼紝閮藉繀椤诲鐞哱nend;
璇ヨ鍙ュ鐞嗗紓甯革紝鍙瑙﹀彂寮傚父锛岀郴缁熻嚜鍔ㄦ崟鎹夎瑙﹀彂鐨勫紓甯革紝鐒跺悗浠ヤ俊鎭璇濇鐨勬柟寮忔樉绀哄紓甯镐俊鎭紝璁╃▼搴忛伩寮€鍙戠敓寮傚父鐨勪唬鐮侊紝鐒跺悗缁х画鍚戜笅鎵ц銆俓u003c/span>
杩欑寮傚父澶勭悊缁撴瀯涓€鑸敤浜庝繚鎶ょ郴缁熻祫婧愬垎閰嶇瓑鏂归潰锛屽畠纭繚浜嗘棤璁簍ry浣撳唴鐨勪唬鐮佹槸鍚﹀彂鐢熷紓甯革紝閮介渶瑕佺敱绯荤粺杩涜鏈€鍚庣殑缁熶竴澶勭悊涓€浜涘绯荤粺瀵硅薄鐨勬纭鐞嗐€傘€€銆€
鍜宼ry鈥xcept鈥nd涓嶅悓锛岃缁撴瀯鐨刦inally閮ㄥ垎鎬昏鎵ц銆傚湪try-finally璇彞涓紝褰搕ry閮ㄥ垎浜х敓寮傚父鍚庯紝搴旂敤绋嬪簭鐩存帴鎵цFinally閮ㄥ垎鐨勮祫婧愰噴鏀捐鍙ャ€俓u003c/span>
绀轰緥锛歕u003c/span>
杩愯鏃剁晫闈㈠涓嬪浘鎵€绀猴細
绀轰緥浠g爜锛歕u003c/span>
implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);var i: ^integer; res, y: double;begin try new(i); i^ := strtoint(edit1.Text); y := 3.1415926; res := y/i^; label1.Caption := '3.1415926 div ' inttostr(i^) ' = ' floattostr(res); finally showmessage('鐜板湪閲婃斁i^鐨勫唴瀛榎u0026#39;); dispose(i); end;end;end.
2.try...except...end
璇硶鏍煎紡锛歕u003c/span>
try <琚繚鎶よ鍙u0026gt;except 寮傚父澶勭悊璇彞 //寮傚父涓嶅彂鐢燂紝涓嶅鐞哱nend;鎴朶ntry <琚繚鎶よ鍙u0026gt;except on <寮傚父瀵硅薄绫诲瀷1> do <璇彞1> //鎹曡幏鎸囧畾绫诲瀷鐨勫紓甯稿璞★紝杩涜澶勭悊 ...... on <寮傚父瀵硅薄绫诲瀷n> do <璇彞n> //鎹曡幏鎸囧畾绫诲瀷鐨勫紓甯稿璞★紝杩涜澶勭悊 else <璇彞n 1> //缂虹渷鐨勫紓甯稿鐞嗕唬鐮乗nend;
鍦╰ry浣撳唴鐨勪唬鐮佸彂鐢熷紓甯告椂锛岀郴缁熷皢杞悜except閮ㄥ垎杩涜寮傚父鐨勫鐞嗐€傝繖鏄疍elphi澶勭悊寮傚父鐨勬渶鍩烘湰鐨勬柟寮忎箣涓€銆倀ry璇彞鍧楁寚鍑轰簡闇€瑕佽繘琛屽紓甯镐繚鎶ょ殑浠g爜銆傚鏋滃湪杩欓儴鍒嗘湁涓嶆甯哥殑浜嬩欢鍙戠敓锛屽垯寮曞彂涓€涓紓甯稿璞°€俥xcept鏄紓甯稿鐞嗛儴鍒嗭紝琚繚鎶ら儴鍒嗗紩鍙戠殑寮傚父瀵硅薄灏嗘墽琛孿u0026lt;寮傚父澶勭悊璇彞>鎴栫敱杩欓儴鍒嗕唬鐮佹崟鑾峰苟杩涜澶勭悊銆俓u003c/span>
浣跨敤璇ヨ鍙ュ鐞嗗紓甯告椂锛屼細鏍规嵁寮傚父鐨勭被鍨嬩笉鍚岋紝瀵瑰紓甯稿仛涓嶅悓鐨勫鐞嗐€俓u003c/span>
鍦ㄥ墠闈㈢殑鑷畾涔夊紓甯镐唬鐮佺ず渚嬩腑宸茬粡浣跨敤杩囪璇彞锛屾墍浠ュ湪姝や笉鍐嶄妇渚嬨€俓u003c/span>
红蜘蛛有哪些防治技巧?采取哪些方法、选用哪些药物防治最有效?
今天,农技小背篓给大家说一说防治红蜘蛛这种害虫的技术知识吧。因为本文内容比较细、知识点比较多,所以篇幅比较长,全文一共6620余字,大家看完照着做,基本上就可以杜绝红蜘蛛虫害防治方面的困扰。
现在已经立秋了,也就又到了红蜘蛛虫害全年爆发虫害最严重的时期了(红蜘蛛虫害,秋季9-10月份最严重,其次是春季4-6月份,最适合红蜘蛛快速爆发的温湿度条件是温度26-28度、湿度40-60%左右),因为秋季高温干燥的气候环境非常有利于红蜘蛛这种害虫的快速繁殖孵化、快速扩散传播、快速爆发严重虫害(红蜘蛛属于高温干旱型的害虫类型,但温度超过33-35度时会抑制红蜘蛛虫害的发生)。
提到红蜘蛛这种小害虫,农技小背篓估计绝大数喜欢种植的人在红蜘蛛的防治上都很头疼——虫害不知不觉就发生、虫害反复循环不除根,明明打了杀虫剂但就是不管用,不论打几遍药,可作物上、果树上、花卉上、瓜果蔬菜上的红蜘蛛就是灭杀不干净,而且经常明明刚打药没几天,作物和花卉等植物上又突然大面积出现了红蜘蛛。
为此,很多人虽然对红蜘蛛这种小害虫是恨之入骨,但偏偏又没有好办法去把彻底干掉、彻底灭杀干净,只能一边无奈的去一遍一遍打着好像杀不死红蜘蛛的杀虫剂,另一边又只能眼巴巴的看着红蜘蛛循环反复的去危害自己辛苦种植的各类作物、花卉、果树等植物。
为了帮助大家解决困扰,所以呢,今天农技小背篓就给大家说一说红蜘蛛这种顽疾性害虫防治的综合技术知识,希望大家赶紧认真看一看、学一学、用一用,不然大家又要在接下来的秋季红蜘蛛虫害防治上“犯头疼”了。
原因分析:红蜘蛛虫害为什么总是防不住、杀不死、除不净?
(一)虫害防治的观念、选药、打药不对路
1、虫害发生前不重视防范,虫害爆发后才想着去打药
第一点,红蜘蛛这种害虫,具有很强的生存能力、繁殖能力、藏匿能力、抗药能力,前期不注意通过加强水、温、肥、药、土及田间管理等多方面去重点预防红蜘蛛,一旦等到红蜘蛛在你家地里的农作物或你家的花卉苗木上大面积出现了,再想去通过打药杀虫的方法去灭杀干净、彻底除根,不但防治难度大、也很难除根,只能落个“经常打药经常防治、经常防治又防不住”的结果。
第二点,红蜘蛛个头小,作物或花卉上刚出现虫害时,一般在植株底部叶片的背面上会有少量的虫卵和零星几只成虫(这时候就打药灭杀虫源控制虫害的效果最好),但如果大家不翻开植株底层的叶片认真查看,一般都不会知道红蜘蛛虫害已经发生了,等到在地上茎叶的正面发现红蜘蛛到处缓慢爬动时或者看见叶片表面已经大量出现小黄斑点了,这时候说明虫害已经很严重了,这个时候大家再打药防治的效果就会一差千里。
2、使用的杀虫剂不对或者杀虫剂杀螨不杀卵、杀卵不杀螨
红蜘蛛学名叫做叶螨,它在本质上是一种螨虫,防治螨虫和防治其他害虫不同,如果大家防治红蜘蛛时选择的药物不对路(很多常用性的杀虫剂根本不能防治红蜘蛛),或者大家防治红蜘蛛时只使用了能灭杀螨虫但不能灭杀红蜘蛛虫卵的杀虫剂(红蜘蛛害虫有卵、幼螨、若螨、成螨四种形态),在此种情况下,大家虽然觉得打了杀虫剂,但实际上是根本不能彻底灭杀干净或彻底除根红蜘蛛这种虫害的,因为你把红蜘蛛的成虫杀死了,等过几天虫卵孵化、幼虫长大后,作物和花卉上的红蜘蛛一定就会再次卷土重来而大面积爆发虫害。
3、打药防治红蜘蛛时打药马马虎虎既不全面又不到位
很多人在田间打药防治病害、虫害时(大部分带“螨”的杀虫剂都可以防治红蜘蛛),普遍存在打药粗糙马虎不全面不细腻不深入、打药只喷打叶片正面而不喷打叶片背面、只打植物植株不打地面的情况,这种打药的方法,不论是防治病害还是防治虫害,一般都很难起到“药到病除、药到虫死”的效果。
因为潜藏在植株枝叶/叶柄/树皮缝隙里、潜藏在植物叶片背面、潜藏在花瓣中、潜藏在芯叶中、潜藏在地表土壤缝隙中的病菌和害虫,根本接触不到大家所喷打的药液,尤其是红蜘蛛喜欢藏匿在叶片背面、土壤缝隙、枝干粗皮等隐蔽部位的害虫,如果打药不全面、不细致、不深入,那么大家虽然打了杀虫剂其实就跟没打差不多,但只能杀死表面上的红蜘蛛却不能杀不死藏匿起来的红蜘蛛,这又如何能起到干净灭杀害虫、彻底根除害虫的效果呢,由此大家经常打药后虫害再次死灰重燃卷土重来也就不足为奇了。
4、长期单一用药造成红蜘蛛的抗药性越来越强、打药越来越难杀死
长期以来,红蜘蛛一直都是危害各类植物上“常客”,咱们种植农作物、种植花卉苗木的朋友也就需要连年频繁地去打药防治,而且在药物防治上经常是遇到哪种效果好的杀虫剂就一直长期使用这种药物,打药时又不注意配施有机硅等药物增效剂,从而导致红蜘蛛随着一代一代的交替而逐步增强了对药物的抵抗性,由此造成红蜘蛛对过去常用的很多杀虫剂产生了很强药物抗性而出现了打药后杀不死、除不干净红蜘蛛的现象。
(二)不能根据红蜘蛛的虫害特性规律去防治
1、红蜘蛛食物杂、分布广、善隐藏、繁殖快、群体大,会加大红蜘蛛防治的难度。
第一点,红蜘蛛是一种很是常见的螨虫,它可以广泛寄生分布在小麦、玉米、水稻、大豆、棉花以及其他各种常见性的果树作物、瓜果蔬菜、花卉苗木、各类杂草等一百多种植物上进行取食危害,主要在叶片背面潜藏和产卵,通过吸取这些植物上新稍、嫩叶、幼果等(主要危害叶片)汁液为进行危害,造成受害植物叶片上出现小黄斑点、发黄灰白、萎焉焦枯、过早凋落甚至死苗死棵等虫害问题,进而造成作物因虫害而出现生长不动、长势不良、开花结果异常、产量品质降低等减产损失。
第二点,红蜘蛛属于喜欢高温干旱环境的虫害,在正常情况下,气温越高、下雨越少、天气越干燥的情况下,红蜘蛛的活性越强、产卵数量越多、孵化传播速度越快,尤其在温暖少雨的春季4-6月份和高温干燥的9-10月份是红蜘蛛最容易泛滥的虫害爆发高峰季节,而且红蜘蛛虫害在秋季比在春季更严重。
第三点,红蜘蛛这种害虫还具有一个非常让人难防治的特点,那就是从3月份天气变暖后(逐步开始繁殖孵化扩散)到11月份天气变冷前(陆续越冬休眠到第二年继续繁殖危害),红蜘蛛 便会一代接一代的繁殖几代甚至十几代(一只红蜘蛛一代就能繁殖百余只虫卵),尤其在秋季高温干燥的环境下三五天就能繁殖一代(一周打药一次也赶不上虫害繁殖的速度),这些一代接一代繁殖孵化的红蜘蛛会在植物上、田地里世代叠加进行危害(期间红蜘蛛会在不同植物上转移持续危害),由此造成上一代红蜘蛛还没有没干净、下一代红蜘蛛又泛滥成灾、一代更比一代更严重的情况(虫害高发期红蜘蛛数量成倍增加)。
2、红蜘蛛虫害的4种虫态和3个危害期(多种虫态混合发生和虫害早期不容易发现),是造成红蜘蛛防治困难的重要原因。
红蜘蛛个头不大,但它却又卵、幼螨、若螨、成螨4种形态。其中,对作物和花卉危害最严重的就是成螨(红蜘蛛成虫),而未孵化的虫卵和刚孵化的幼螨若虫是下一步危害植物的主力军,这个时候必须抓紧打药防治。
红蜘蛛虫害期可以分为危害初期、危害中期、危害后期3个阶段。其中,
①红蜘蛛危害初期时可以在植物叶片背面(主要是下部叶片背面)看到很多针尖大小的白色虫卵和少量的成虫(卵多、虫少),但此时植物叶片表面上基本看不出任何虫害症状;
②红蜘蛛危害中期时可以看到植物叶片背面的白色虫卵和成虫大幅增加(此时虫卵和成虫差不多各占一半),而且此时植物叶片正面上会出现很多红蜘蛛啃咬破坏的虫害痕迹,而且叶片正面上也能直观看见很多由于红蜘蛛把叶片蛀空的小黄斑点,这个时候打药就有些晚了;
③红蜘蛛危害后期时植物叶片背面密密麻麻都是红蜘蛛成虫且还有少量正在孵化的虫卵(此时成虫多、虫卵少),而且这些红蜘蛛会扩散到周边的枝条、叶片、地面上(地面上和植株上到处都能见到乱爬的红蜘蛛),更加严重时受害植株上还会出现类似蜘蛛网一样的网丝物(这也是为什么红蜘蛛名字里有个“蜘蛛”的原因),这个时候5-7天打药一次都未必能控制得住虫害。
总结经验:怎样才能彻底有效地控制与防治住红蜘蛛虫害?
防治红蜘蛛,最关键的方法是多措并举、综合管理去控制源头预防虫害,最重要的手段就是选对药物、科学打药去针对性灭杀避免继续扩散传播。
(一)关于红蜘蛛虫害的药物防治
打药防治红蜘蛛,是大家防治红蜘蛛最常用且防治红蜘蛛最直接的方法,为此,农技小背篓想给大家说一说如何选药、选哪种药、怎么打药才能防治住红蜘蛛虫害。
1、选用既能杀螨又杀卵的药物才有效,杀螨不杀卵或杀卵不杀螨的药物防治不住红蜘蛛
第一点,上面农技小背篓已经给重点强调过:红蜘蛛有卵、幼螨、若螨、成螨四种虫态,而且这四种虫态叠加累积同时发生(有时一个叶片上就有四种不同虫态的红蜘蛛),但目前市面上根本没有能够同时灭杀红蜘蛛四种虫态的特效药物,如果大家只使用杀螨不杀卵或只杀卵不杀螨或者不具备同时灭杀多种虫态红蜘蛛的药物,那么大家打药后就无法彻底切断红蜘蛛继续繁殖扩散传播的途径,也就不能从根本上根除红蜘蛛虫害,大家打药后就容易发生红蜘蛛数天后卷土重来的问题。
第二点,防治红蜘蛛必须要使用对灭杀红蜘蛛有明显效果的药物,因为市面上大家常用的很多杀虫剂能杀其他害虫(红蜘蛛是螨虫而不是昆虫),但它们根本杀不死红蜘蛛或者防治红蜘蛛的效果非常差,如果大家不注意有针对性的挑选杀虫剂,那么大家打药后就根本杀不死红蜘蛛。
2、防治红蜘蛛最有效的几种药物与配方
上面农技小背篓也已经给大家强调过:目前根本找不到能够具备同时灭杀卵、幼螨、若螨、成螨四种虫态红蜘蛛的特效药,所以,大部分情况下单一打药是控制不住红蜘蛛的,一般情况下,防治红蜘蛛使用不同药物复配才是最有效、最正确的做法。
第一点,以田间防治红蜘蛛的效果来看,目前防治红蜘蛛的常用且有效药物主要是名称中带“螨”的杀虫剂,比如说哒螨灵、螺螨酯、乙螨唑、四螨嗪、炔螨特、乙唑螨腈、丁氟螨酯、噻螨酮等单剂型药物,比如说炼精乙螨唑、阿维乙螨唑、阿维螺螨酯等复配药物,除此之外还有阿维菌素、矿物油、联苯肼 酯、石硫合剂、三唑锡、丁醚脲等不带“螨”字但又能防治红蜘蛛的药物。
不过大家大家需要注意的是,上述的这些药物一般只能灭杀红蜘蛛四种不同虫态中的2-3种,而且红蜘蛛对上述药物中的一些药物已经产生了药物抗性,因此,单独使用上述药物的虫害防治效果并不是太好,大部分情况下我们只有把它们进行2-3种复配后使用才能取得更加显著的红蜘蛛综合防治效果。
第二点,从既能杀螨杀卵的红蜘蛛防治药物上来说,农技小背篓给大家推荐几个能够同时灭杀红蜘蛛螨虫和虫卵的用药配方,以供大家参考借鉴:(1)阿维菌素 螺螨酯;(2)阿维菌素 哒螨灵;(3)阿维菌素 四螨嗪;(4)阿维菌素 噻螨酮;(5)阿维菌素 乙螨唑;(6)阿维菌素 丁醚脲;(7)联苯肼 酯 乙螨唑;(8)炔螨特 矿物油;(9)联苯肼酯 乙螨唑或乙唑螨腈或螺螨酯或丁醚脲;(10)乙螨唑 螺螨酯或丁醚脲;(11)阿维菌素 矿物油 哒螨灵;(12)乙螨唑 大蒜精油 苦参碱;(13)阿维菌素 乙螨唑 螺螨酯;(14)阿维菌素 联苯肼酯 丁醚脲;(15)联苯肼酯 乙螨唑 哒螨灵;等等。
第三点,在红蜘蛛防治的用药注意事项上来说,大家用药时一定要注意以下几点:
①不同杀螨型的杀虫剂复配使用比单独使用效果好;②复配防治红蜘蛛的药物时,一般2-3种最合适,但药物中既要有杀螨的药物成分也要有杀卵的药物成分;③防治红蜘蛛的药物配方不能长期固定使用一个,并且任何一种药物当季使用次数不可超过2-3次,以防长期固定用药而增强红蜘蛛的抗药性,建议大家选几种药物、几个配方交替着使用,比如说阿维菌素、哒螨灵、螺螨酯、乙螨唑、四螨嗪、炔螨特、矿物油、联苯肼酯、等药物交替着复配使用;④不同季节虫害特点要注意选择不同的药物,比如四螨嗪、螺螨酯、乙螨唑、灭螨净等药物比较适合在早春防治红蜘蛛使用,石硫合剂、矿物油、四螨嗪等药物适合在冬季果树清园时使用,联苯肼酯、阿维菌素、螺螨酯、哒螨灵、炔螨特等药物适合在红蜘蛛螨虫高发期时使用,等等。
3、打药灭杀红蜘蛛时务必要全面、彻底、高效
第一点,药物打药时选用雾化好的喷头,先由上向下打药,然后再由下向上打药,不但要仔细喷打植物地上的茎叶,而且也要仔细喷打植物根基部的地面土壤,不仅要喷打植物的茎叶正面,而且更要重点喷打植物的叶面背面和叶梗部位,不仅要喷打农田中的作物和地面,而且也要喷打农田周边的杂草和地面。除此之外,因为大部分防治红蜘蛛的药物都没有内吸传导性,所以打药时必须全面、细腻、周到、打透、打湿润,只要药液接触不到红蜘蛛的虫体和虫卵,打药后就很难彻底杀死各种虫态的红蜘蛛。
第二点,药物防治红蜘蛛时,应当从3月份天气刚变暖时且气温回升到10-15度及以上、叶片上8-10个虫卵或有3-5头红蜘蛛时,此时必须立即打第一遍药进行灭杀越冬虫源(第一遍药要尽量早打,因为此时预防全年红蜘蛛虫害的关键期),在春季和秋季红蜘蛛虫害高发期的4-5月和9-10月(6/7/8月雨季湿度大虫害轻)必须重点打药2-3次进行防治,如果是果树作物,要抓住春稍生长期、花前2周、谢花2周、秋稍生长期、果实膨大期、落叶后、冬季清园等几个关键期进行药物防治。
第三点,红蜘蛛高发期打药时,虫害不严重时或空气湿度交大时可以7-10天打药一次,虫害严重时或空气干燥时5-7天就要打药一次,虫害更加严重时甚至有必要3-5天打药一次,一般需要连续交替打药2-3次才能控制住红蜘蛛的繁殖与扩散。
第四点,对于红蜘蛛虫害严重且红蜘蛛抗药性强的农田,打药时建议搭配有机硅、大蒜精油、矿物油等药物增效剂一起使用来提高红蜘蛛的灭杀防治效果,因为这些增效剂能够提高药液的渗透性和延展性。
第五点,药物防治红蜘蛛遇到温度高且空气干燥的情况时,打药时一定要多用水把药液打足打透保证湿度,或者打药后第二天再用清水喷淋一下叶片增加湿度,因为空气太干燥会有利于红蜘蛛的存活、不利于药物对红蜘蛛的防治。
第六点,温度较高的春秋季节红蜘蛛高发期打药防治虫害时,建议在下午十分打药,这样可以让药液更慢地蒸发、更长时间的润湿茎叶,这种做法对灭杀红蜘蛛有很好的帮助作用。
(二)红蜘蛛防治一定不能忽视的其他几项管理手段
第一点,红蜘蛛在高温干燥的环境下产卵多、繁殖快、孵化快、爆发虫害速度快、虫害危害程度中,而且温度越高、空气越干燥,虫害爆发危害就越重,因此,在春秋两季红蜘蛛最容易爆发的季节,不论种植各类农作物还是种植各类花卉苗木,都应当在早晚经常浇水保持土壤湿润,或者在早晚经常茎叶喷淋清水增加空气湿度,这样对于控制和减少红蜘蛛虫害会非常有帮助。
第二点,红蜘蛛在通风不良或密不透风的环境下更容易爆发,因此,大家要想防治红蜘蛛虫害,采取保持田间合理种植密度,及时做好田间作物的修剪、整枝、吊蔓、打杈、疏老叶等管理,同时要避免过量使用氮肥刺激作物发生茎叶旺长,以此最大程度的增加田间作物枝叶的透风性,这些对于防治红蜘蛛也会有比较好的帮助作用。
第三点,红蜘蛛的寄生场所和寄生植物比较多,因此,大家在种植作物和花卉等植物时,一方面要提前半个月深暴晒土壤来破坏红蜘蛛寄生的环境场所、消灭藏在表土层中的虫与卵,另一方面打杀虫剂和除草剂时也要把地头地边的杂草一起仔细喷打清理干净,否则即使把地里的红蜘蛛杀死了,但地边地头的红蜘蛛还会继续扩散传播到地里反复引发虫害。
第四点,红蜘蛛在春秋高发期时,建议每隔2-3天就翻看一下田地中作物和花盆中花卉底部的叶片背面,一单发现有红蜘蛛的虫卵或成虫痕迹,农田作物必须立即打药防治,花卉可以立即把有虫卵和成虫的叶片摘除掉,然后全面淋浇杀螨剂药液进行防控,最后放在透风条件好的地方定期浇水预防。
第五点,对于种植果树苗木的朋友来说,大家可以在天气变冷红蜘蛛越冬休眠前,在树木的茎秆大枝上绕缠上一些稻草束或废布条或旧报纸等,这样可以引诱准备越冬的红蜘蛛扎堆聚集,等到冬季快结束之前把这些茎秆大枝上的缠绕物取下来集中焚烧掉即可,或者结合冬季清园清刮树体老翘皮时用自制的石灰水或购买的涂白剂涂刷树木的主干大枝,这样可以一次性消灭掉大量的越冬红蜘蛛虫源。
第六点,对于不能打药防治红蜘蛛的保护地,大家可以通过保护或释放草蛉、花蝽、瓢虫等昆虫来自然消灭红蜘蛛,因为这些昆虫都是以捕捉红蜘蛛为食的天敌生物。
好了,关于红蜘蛛防治的知识就先给大家介绍这么多吧,虽然这篇文章比较长,但如果大家能够切实做到上述管理,或者从春季3月中旬天气变暖后到11月初天气变冷前做好全年药物周期防治,那么基本上完全有能力防治住一年到头循环出现的红蜘蛛,有能力把田间作物上的红蜘蛛螨虫数量和虫害程度控制在很低的水平,否则,大家也许就会在红蜘蛛防治上面临着“年年打药年年防治,天天打药天天防不住,红蜘蛛危害一茬更比一茬重”的尴尬局面。
点击上方“关注”农技小背篓 每日了解更多实用的农技知识