Android之AsyncTask异步任务详解总结

Android 多线程----AsyncTask异步任务详解

【正文】

本文将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信。

一、Android当中的多线程:

在Android当中,当一个应用程序的组件启动的时候,并且没有其他的应用程序组件在运行时,Android系统就会为该应用程序组件开辟一个新的线程来执行。默认的情况下,在一个相同Android应用程序当中,里面的组件都是运行在同一个线程里的,这个线程称之为Main线程。当我们通过某个组件来启动另一个组件的时候,这个时候默认都是在同一个线程当中完成的。当然,我们可以自己来管理我们的Android应用的线程,我们可以根据我们自己的需要来给应用程序创建额外的线程。

二、Main Thread 和 Worker Thread:

在Android当中,通常将线程分为两种,一种叫做Main Thread,除了Main Thread之外的线程都可称为Worker Thread。

当一个应用程序运行的时候,Android操作系统就会给该应用程序启动一个线程,这个线程就是我们的Main Thread,这个线程非常重要,它主要用来加载UI界面,完成系统和用户之间的交互,并将交互后的结果又展示给用户,所以Main Thread又被称为UI Thread。

Android系统默认不会给应用程序组件创建一个额外的线程,所有的这些组件默认都是在同一个线程中运行。然而,某些时候当我们的应用程序需要完成一个耗时操作的时候(如访问网络或者是对数据库进行查询),此时UI Thread就会被阻塞。例如,当我们点击一个Button,然后希望其从网络中获取一些数据,如果此操作在UI Thread当中完成的话,UI线程就会处于阻塞的状态,此时,我们的系统不会调度任何其它的事件,更糟糕的是,当我们的整个现场如果阻塞时间超过5秒钟(官方描述),这个时候就会出现 著名的ANR (Application Not Responding)的问题,此时,应用程序会弹出一个框,让用户选择是否退出该程序。对于Android开发来说,出现ANR的现象是绝对不能被允许的。

另外,由于Android UI控件不是线程安全的,所以我们不能在UI Thread之外的线程当中对UI控件进行操作。因此在Android的多线程编程当中,有两条非常重要的原则必须遵守:

  • 不能在UI Thread当中进行耗时操作,以免阻塞UI Thread
  • 不能在UI Thread之外的线程当中操纵UI元素

 三、如何处理UI Thread 和 Worker Thread之间的通信:

我们既不能在主线程当中处理耗时的操作,又不能在工作线程中来访问我们的UI控件,那么我们比如从网络中要下载一张图片,又怎么能将其更新到UI控件上呢?这就关系到了主线程和工作线程之间的通信问题了。在Android当中,提供了异步消息处理机制的两种方式来解决线程之间的通信问题,一种是通过Handler的机制(这种方式在后面的博客中将详细介绍),还有一种就是今天要详细讲解的 AsyncTask 机制

四、AsyncTask:

AsyncTask:异步任务,从字面上来说,就是在UI主线程运行的时候,异步完成一些操作。AsyncTask允许我们在后台执行一个异步任务。我们可以将耗时的操作放在异步任务当中来执行,并随时将任务执行的结果返回给UI线程来更新UI控件。通过AsyncTask我们可以轻松解决多线程之间的通信问题。

怎么来理解AsyncTask呢?通俗来说,AsyncTask就相当于Android给我们提供了一个多线程编程的一个框架,其介于Thread和Handler之间,我们如果要定义一个AsyncTask,就需要定义一个类来继承AsyncTask这个抽象类,并实现其唯一的一个 doInBackgroud 抽象方法。

要掌握AsyncTask,我们就必须要一个概念,总结起来就是: 3个泛型,4个步骤

我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,需要为其指定3个泛型参数:

AsyncTask <Params, Progress, Result>
  • Params: 指定的是我们传递给异步任务执行时的参数的类型
  • Progress: 指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
  • Result: 指定的是异步任务执行完后返回给UI线程的结果的类型

 我们在定义一个类继承AsyncTask类的时候,必须指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void,例如:

AsyncTask <Void, Void, Void>

4个步骤:当我们执行一个异步任务时,需要按照下面的4个步骤分别执行:

  • onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出ProgressDialog
  • doInBackground(Params... params): 在onPreExecute()方法执行完后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行这个方法(即在worker thread当中执行),执行完后将执行结果发送给最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
  • onProgressUpdate(Progess... values): 这个方法也是在UI Thread当中执行的,在异步任务执行的时候,有时需要将执行的进度返回给UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用一个 publishProgress(Progress) 的方法来将进度时时刻刻传递给 onProgressUpdate 方法来更新
  • onPostExecute(Result... result): 当异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上

 为什么AsyncTask抽象类只有一个 doInBackground 的抽象方法呢??原因是,我们如果要做一个异步任务,我们必须要为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,我可能并不需要弹出ProgressDialog,并不需要随时更新ProgressDialog的进度条,也并不需要将结果更新给UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,因此必须要实现的方法是 doInBackground 方法。

4个步骤简洁版描述如下:

  第一步:表示任务执行前的操作

  第二步:主要完成耗时操作

  第三步:主要是更新UI操作

  第四步:产生最终结果

以下实例中代表的含义为:

  第一步:显示进度条

  第二步:(此任务必不可少)在后台执行任务,将进度值传给第三步,将结果传给第四步;

  第三步:进度值更新

  第四步:产生最终结果

 

五、【实例】通过AsyncTask来从网络上下载一张图片:

下面通过两个代码示例,来看看如何通过AsyncTask来从网络上下载一张图片,并更新到ImageView控件上。

在这之前,必须要执行的操作是:添加网络授权。下面的例子将有详细的操作描述。

【实例一】从网络下载图片,弹出一个ProgressDialog,但不显示实时进度:

1、添加网络授权:

因为手机默认不能访问网络,所以首先要在清单文件 AndroidManifest.xml中添加网络授权。

加上<uses-permission android:name="android.permission.INTERNET"/>

2、完整版代码如下:

activity_main.xml的代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" ><ImageViewandroid:id="@+id/imageView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_centerHorizontal="true" /><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:layout_marginBottom="136dp"android:text="下载网络图片" />
</RelativeLayout>
MainActivity.java的代码:

package com.example.downloadimage01;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {private ImageView imageView ;private Button button ;   private ProgressDialog dialog ;//来自网络的图片private String image_path = "http://imgsrc.baidu.com/forum/pic/item/7c1ed21b0ef41bd51a5ac36451da81cb39db3d10.jpg" ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//添加弹出的对话框dialog = new ProgressDialog(this) ;dialog.setTitle("提示") ;dialog.setMessage("正在下载图片,请稍后···") ;imageView = (ImageView)findViewById(R.id.imageView1) ;button = (Button)findViewById(R.id.button1) ;button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {//点击按钮时,执行异步任务的操作new DownTask().execute(image_path) ;}}) ;   //注意,这个地方的分号容易遗忘}/* * 异步任务执行网络下载图片* */public class DownTask extends AsyncTask<String, Void, Bitmap> {//上面的方法中,第一个参数:网络图片的路径,第二个参数的包装类:进度的刻度,第三个参数:任务执行的返回结果@Override//在界面上显示进度条protected void onPreExecute() {dialog.show() ;};protected Bitmap doInBackground(String... params) {  //三个点,代表可变参数//使用网络链接类HttpClient类完成对网络数据的提取HttpClient httpClient = new DefaultHttpClient() ;HttpGet httpget = new HttpGet(params[0]) ;Bitmap bitmap = null ;try {HttpResponse httpResponse = httpClient.execute(httpget) ;if(httpResponse.getStatusLine().getStatusCode()==200){HttpEntity httpEntity = httpResponse.getEntity() ;byte[] data = EntityUtils.toByteArray(httpEntity);bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);}}  catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return bitmap;}//主要是更新UI@Overrideprotected void onPostExecute(Bitmap result) { super.onPostExecute(result);imageView.setImageBitmap(result) ;//更新UIdialog.dismiss() ;                }        }@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}

运行后,点击按钮,显示结果如下:

【实例二】从网络下载图片,弹出能显示进度值的对话框:

注:既然要显示进度值,所以此处的进度条风格要设置为水平。

1、添加网络授权(同上)

2、完整版代码如下:

activity_main.xml的代码和【实例一】中的一样;

MainActivity.java的代码:

package com.example.smyh001downloadimage01;import java.io.ByteArrayOutputStream;
import java.io.InputStream;import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;public class MainActivity extends Activity {private ImageView imageView ;private Button button ;   private ProgressDialog dialog ;//来自网络的图片private String image_path = "http://imgsrc.baidu.com/forum/pic/item/7c1ed21b0ef41bd51a5ac36451da81cb39db3d10.jpg" ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//添加弹出的对话框dialog = new ProgressDialog(this) ;dialog.setTitle("提示") ;dialog.setMessage("正在下载图片,请稍后···") ;//将进度条设置为水平风格,让其能够显示具体的进度值dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) ;dialog.setCancelable(false) ; //用了这个方法之后,直到图片下载完成,进度条才会消失(即使在这之前点击了屏幕)imageView = (ImageView)findViewById(R.id.imageView1) ;button = (Button)findViewById(R.id.button1) ;button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {//点击按钮时,执行异步任务的操作new DownTask().execute(image_path) ;}}) ;   //注意,这个地方的分号容易遗忘}    /* * 异步任务执行网络下载图片* */public class DownTask extends AsyncTask<String, Integer, byte[]> {//上面的方法中,第一个参数:网络图片的路径,第二个参数的包装类:进度的刻度,第三个参数:任务执行的返回结果@Override//在界面上显示进度条protected void onPreExecute() {dialog.show() ;};protected byte[] doInBackground(String... params) {  //三个点,代表可变参数//使用网络链接类HttpClient类完成对网络数据的提取,即完成对图片的下载功能HttpClient httpClient = new DefaultHttpClient() ;HttpGet httpget = new HttpGet(params[0]) ;byte[] result = null ;ByteArrayOutputStream outputStream = new ByteArrayOutputStream() ;InputStream inputStream = null ;try {HttpResponse httpResponse = httpClient.execute(httpget) ;if(httpResponse.getStatusLine().getStatusCode()==200){HttpEntity httpEntiry = httpResponse.getEntity();inputStream = httpEntiry.getContent();//    先要获得文件的总长度long file_length = httpResponse.getEntity().getContentLength() ;int len = 0 ;//    每次读取1024个字节byte[] data = new byte[1024] ;  //    每次读取后累加的长度int total_length = 0 ;          while ((len = inputStream.read(data))!=-1) {//    每读一次,就将total_length累加起来total_length+=len ;//    得到当前图片下载的进度int progress_value = (int) ((total_length / (float)file_length)*100);//    时刻将当前进度更新给onProgressUpdate方法publishProgress(progress_value) ;outputStream.write(data, 0, len);}//    边读边写到ByteArrayOutputStream当中result = outputStream.toByteArray();//bitmap = BitmapFactory.decodeByteArray(result, 0, result.length) ;}}  catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {httpClient.getConnectionManager().shutdown();}return result;}@Overrideprotected void onProgressUpdate(Integer... values) {// TODO Auto-generated method stubsuper.onProgressUpdate(values);//    更新ProgressDialog的进度条dialog.setProgress(values[0]);}//主要是更新UI        @Overrideprotected void onPostExecute(byte[] result) { super.onPostExecute(result);//    将doInBackground方法返回的byte[]解码成要给BitmapBitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length) ;//    更新我们的ImageView控件imageView.setImageBitmap(bitmap) ;//更新UI//    使ProgressDialog框消失dialog.dismiss() ;    }        }@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}
运行后,显示结果如下:




六、AsyncTask的重要知识点:

明白了AsyncTask的工作原理后,继续补充一下AsyncTask的一些其他知识点:

1、Cancelling a Task

我们可以在任何时刻来取消异步任务的执行,通过调用 cancel(boolean)方法,调用完这个方法后系统会随后调用 isCancelled() 方法并且返回true。如果调用了这个方法,那么在 doInBackgroud() 方法执行完之后,就不会调用 onPostExecute() 方法了,取而代之的是调用 onCancelled() 方法。如果有必要的话,为了确保Task已经被取消了,我们需要经常调用 isCancelled() 方法来判断。

2、在使用AsyncTask做异步任务的时候必须要遵循的原则:

  • AsyncTask类必须在UI Thread当中加载,在Android Jelly_Bean版本后这些都是自动完成的
  • AsyncTask的对象必须在UI Thread当中实例化
  • execute方法必须在UI Thread当中调用
  • 不要手动的去调用AsyncTask的四个方法,这些都是由Android系统自动调用的
  • AsyncTask任务只能被执行一次

 

【总结】

到此,有关AsyncTask的总结就到此为止了,本文主要讲解了Android中的多线程知识,并且详细地讲解了 AsyncTask 异步任务的概念和实现机制,并通过实例来了解 AsyncTask 的执行过程,最后还补充了 AsyncTask 的一些重要知识点,包括如何取消一个 AsyncTask 以及在使用 AsyncTask 时所必须遵循的规则。建议初学者(包括我)在理解这方面的问题时可以多参考官方的API文档。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker源码_使用docker、Jenkins、gitlee、springboot、搭建个人博客网站 并实现CI/CD 外加机器人提醒...

看朱成碧思纷纷&#xff0c;憔悴支离为忆君。--- barcke前言:服务器用的是云服务器买的阿里的linux、jdk1.8、docker服务端使用的为阿里的docker镜像仓库、mysql使用5.7版本的、redis使用最新版即可、文件服务使用的阿里的oss.项目采用jib推送docker镜像.附录: git源码地址—-h…

初次见面,如何令人永远难忘

1 初次见面&#xff0c;如何令人永远难忘2 见到熟人和见到偶像的区别3 真正的好朋友是在最紧急的时刻帮你一把的那个人4 当你正在减肥时&#xff0c;你朋友约你出去吃饭5 被这样的友谊感动到了6 等我老了也要和大爷一样做一个时尚的人不说别的大爷好酷↓ ↓ ↓

号称迄今为止最快,.NET6带来了什么?

北京时间11月8号午夜&#xff0c;.NET6正式发布。该版本经历了一万多次Git提交&#xff0c;号称迄今为止最快的.NET&#xff0c;究竟有哪些亮点呢&#xff1f;1LTS版本&#xff0c;发布前经过了长期的线上生产压力测试&#xff1b;2性能提升&#xff0c;包括文件I/O&#xff0c…

linux 文件系统的管理 (硬盘)

RH133—Unit4 文件系统的管理 一、系统在初始化时如何识别硬盘 1、系统初始时根据MBR的信息来识别硬盘&#xff0c;其中包括了一些执行文件就来载入系统&#xff0c;这些执行文件就是MBR里前面446bytes里的boot loader 程式&#xff0c;而后面的16X4的空间就是存储分区表信息的…

Android之多线程----异步消息处理机制之Handler详解

一、handler的引入&#xff1a; 我们都知道&#xff0c;Android UI是线程不安全的&#xff0c;如果在子线程中尝试进行UI操作&#xff0c;程序就有可能会崩溃。相信大家在日常的工作当中都会经常遇到这个问题&#xff0c;解决的方案应该也是早已烂熟于心&#xff0c;即创建一个…

colorkey唇釉是否安全_colorkey空气唇釉,19/支

国货之光来喽 !!!!超火的colorkey空气唇釉给你们安排上 !!!R601 酒酿梅子超酷超性感的一支 !!这个颜色是偏调但是不显老的深草莓红 一点都不挑皮 谁涂谁白一个度&#xff5e;厚厚的涂一层气场值upup !R608 焦糖红棕偏橘棕调的红棕板栗 !!薄涂厚涂都显白、显气质&#xff01;味道…

初识Ildasm.exe——IL反编译的实用工具(转自Youngman)

Ildasm.exe 概要&#xff1a; 一.前言&#xff1a; 微软的IL反编译实用程序——Ildasm.exe&#xff0c;可以对可执行文件&#xff08;ex&#xff0c;经典的控制台Hello World 的 exe 可执行文件&#xff09;抽取出 IL 代码&#xff0c;并且给出命名空间以及类的视图。在讲述如何…

就想问问你们,这种女朋友从哪里来的?

1 女朋友从哪里来的2 能养好这宠物的对女朋友包容心肯定不赖3 墙都不扶就服这些停车的人4 成功避过所有的球&#xff0c;将白球打入底袋5 谁知道我六年级经历了什么6 这设计&#xff0c;做到了真正意义上的防盗7 这就是我想要的生活面朝大海、春暖花开我也想梦想成真↓ …

基于事件驱动架构构建微服务第10部分:在docker容器内运行单元测试

原文链接&#xff1a;https://logcorner.com/building-microservices-through-event-driven-architecture-part11-run-unit-tests-inside-a-docker-container/在本教程中&#xff0c;我将展示如何在docker容器中运行单元测试。因为我将使用kubernetes在容器中运行微服务&#x…

【iOS-Cocos2d游戏开发之二十】精灵的基础知识点总汇(位图操作/贴图更换/重排z轴等)以及利用CCSprite与CCLayerColor制作简单遮盖层!...

为什么80%的码农都做不了架构师&#xff1f;>>> 李华明Himi 原创,转载务必在明显处注明&#xff1a; 转载自 【黑米GameDev街区】 原文链接: http://www.himigame.com/iphone-cocos2d/516.html 最近写了不少Cocos2d的博文了&#xff0c;那么由于Himi介绍的一般都是…

中柏平板u盘启动_大冶深圳东莞平板硫化机推选得新科技自动化

大冶深圳东莞平板硫化机推选得新科技自动化东莞市得新科技有限公司, 在国内外的销售机器公司。公司位于广东省东莞市。企业致力于点胶设备&#xff0c;硅胶设备&#xff0c;纺织品涂层的先进技术、检测经验发展国外&#xff0c;全面提升国外产品质量&#xff0c;推动国内行业健…

Console-算法-递归算法示例

ylbtech-Arithmetic:Console-算法-递归算法示例1.A&#xff0c;案例-- -- ylb&#xff1a;算法-- type&#xff1a;递归算法-- thankyou:sunshine, 谢谢你的默默付出-- 10:50 2012-04-06-- 1.B&#xff0c;解决方案1.B.1,阶乘 using System;namespace ConsoleApplication1 {cla…

如何才能避免聚会尬聊

全世界只有3.14 % 的人关注了爆炸吧知识如何丰富空闲时光&#xff1f;如何在短时间内获取最最专业的文化、艺术&#xff1f;小编给大家推荐几个公众号它们有趣有颜有料长按二维码&#xff0c;选择“识别图中二维码”关注印客美学id&#xff1a;inkbetter△长按二维码“识别”关…

Excel快速改变行列的次序

改变行列次序是在Excel中常常需要进行的操作&#xff0c;多数用户的方法是先剪切要调整的行或列&#xff0c;然后选定目标位置&#xff0c;单击菜单“插入”→“剪切单元格”。事实上&#xff0c;使用键盘来配合的话&#xff0c;改变行列的次序可以更快捷。比如&#xff0c;在图…

.NET6 如期⽽⾄

.NET6大家好&#xff0c;经过多个月的迭代&#xff0c;.NET 6正式版如期和大家见面了&#xff01;你安装好了吗&#xff1f;还是等等党&#xff1f;希望看完这篇文章你会对.NET 6有更多了解。自2014年11月12日宣布开源后&#xff0c;.NET就成为了一个跨平台、面向多场景的技术。…

Wordpress 提速之 Gzip 压缩

今天来聊下 wordpress 提速&#xff0c;其实关于这方面的话题网上其实蛮多的&#xff0c;速度对一个网站来说无疑是非常重要的&#xff0c;对于速度的追求也是无止境的&#xff0c;在这方面的表率无疑就是 shawn 了&#xff0c;看他博客的很多技巧都是针对速度来的……不过话说…

忍“乳”负重,身材好的女孩子究竟有多不容易?我从科学的角度算出来了……...

全世界只有3.14 % 的人关注了爆炸吧知识大家好&#xff0c;满肚子奇怪知识&#xff0c;用科学眼光看世界的小编又来了。先问大家一个问题&#xff1a;你最喜欢看女孩子的哪里&#xff1f;相信不少人&#xff0c;不论男女都想到了一个地方。不论男女&#xff0c;都希望自己能“大…

getchar()到底怎么用_怎样才能真正发挥肥效,腐植酸水溶肥到底怎么用

施肥是农业生产中的重要环节&#xff0c;不管是大田作物还是花草苗木&#xff0c;水肥充足才能健康生长。而施肥不是看用了多少&#xff0c;而是看转化率&#xff0c;有多少真正被植物所吸收利用。许多化肥看着一大袋一大袋的用&#xff0c;结果都浪费了或者造成徒长一点用处都…

可视化ASP.Net Core Web API健康检查

前言ASP.NET Core提供运行状况检查Middleware和库&#xff0c;以便于报告应用的运行状况。使用方式也很简单。引用Nuget包Microsoft.Extensions.Diagnostics.HealthChecks。然后修改Startup.cs文件:public void ConfigureServices(IServiceCollection services) {...services.A…

利用网站模板创建子网站

1. 打开顶层站点&#xff0c;进入网站内容&#xff0c;最底部&#xff0c;子站点-->新建子网站 2.配置如下&#xff1a; 3. 可能会出现的BUG http://blog.csdn.net/chenxinxian/article/details/12189293 4, 解决方法&#xff1a;安装或卸载用于SharePoint的Reporting Servi…