Android OkHttp完全解析 是时候来了解OkHttp了

 

Android OkHttp完全解析 是时候来了解OkHttp了

标签: AndroidOkHttp
 分类:
【android 进阶之路】(67) 

目录(?)[+]

转载请标明出处: 
http://blog.csdn.net/lmj623565791/article/details/47911083; 
本文出自:【张鸿洋的博客】

一、概述

最近在群里听到各种讨论okhttp的话题,可见okhttp的口碑相当好了。再加上Google貌似在6.0版本里面删除了HttpClient相关API,对于这个行为不做评价。为了更好的在应对网络访问,学习下okhttp还是蛮必要的,本篇博客首先介绍okhttp的简单使用,主要包含:

  • 一般的get请求
  • 一般的post请求
  • 基于Http的文件上传
  • 文件下载
  • 加载图片
  • 支持请求回调,直接返回对象、对象集合
  • 支持session的保持

最后会对上述几个功能进行封装,完整的封装类的地址见:https://github.com/hongyangAndroid/okhttp-utils

使用前,对于Android Studio的用户,可以选择添加:

compile 'com.squareup.okhttp:okhttp:2.4.0'
  • 1
  • 1

或者Eclipse的用户,可以下载最新的jar okhttp he latest JAR ,添加依赖就可以用了。

注意:okhttp内部依赖okio,别忘了同时导入okio:

gradle: compile 'com.squareup.okio:okio:1.5.0'

最新的jar地址:okio the latest JAR


二、使用教程

(一)Http Get

对了网络加载库,那么最常见的肯定就是http get请求了,比如获取一个网页的内容。

//创建okHttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();
//创建一个Request
final Request request = new Request.Builder() .url("https://github.com/hongyangAndroid") .build(); //new call Call call = mOkHttpClient.newCall(request); //请求加入调度 call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(final Response response) throws IOException { //String htmlStr = response.body().string(); } }); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  1. 以上就是发送一个get请求的步骤,首先构造一个Request对象,参数最起码有个url,当然你可以通过Request.Builder设置更多的参数比如:headermethod等。

  2. 然后通过request的对象去构造得到一个Call对象,类似于将你的请求封装成了任务,既然是任务,就会有execute()cancel()等方法。

  3. 最后,我们希望以异步的方式去执行请求,所以我们调用的是call.enqueue,将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。

看到这,你会发现,整体的写法还是比较长的,所以封装肯定是要做的,不然每个请求这么写,得累死。

ok,需要注意几点:

  • onResponse回调的参数是response,一般情况下,比如我们希望获得返回的字符串,可以通过response.body().string()获取;如果希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调用response.body().byteStream()

    看到这,你可能会奇怪,竟然还能拿到返回的inputStream,看到这个最起码能意识到一点,这里支持大文件下载,有inputStream我们就可以通过IO的方式写文件。不过也说明一个问题,这个onResponse执行的线程并不是UI线程。的确是的,如果你希望操作控件,还是需要使用handler等,例如:

    @Override
    public void onResponse(final Response response) throws IOException { final String res = response.body().string(); runOnUiThread(new Runnable() { @Override public void run() { mTv.setText(res); } }); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 我们这里是异步的方式去执行,当然也支持阻塞的方式,上面我们也说了Call有一个execute()方法,你也可以直接调用call.execute()通过返回一个Response

(二) Http Post 携带参数

看来上面的简单的get请求,基本上整个的用法也就掌握了,比如post携带参数,也仅仅是Request的构造的不同。

Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
FormEncodingBuilder builder = new FormEncodingBuilder();   
builder.add("username","张鸿洋"); Request request = new Request.Builder() .url(url) .post(builder.build()) .build(); mOkHttpClient.newCall(request).enqueue(new Callback(){});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

大家都清楚,post的时候,参数是包含在请求体中的;所以我们通过FormEncodingBuilder。添加多个String键值对,然后去构造RequestBody,最后完成我们Request的构造。

后面的就和上面一样了。


(三)基于Http的文件上传

接下来我们在介绍一个可以构造RequestBody的Builder,叫做MultipartBuilder。当我们需要做类似于表单上传的时候,就可以使用它来构造我们的requestBody。

File file = new File(Environment.getExternalStorageDirectory(), "balabala.mp4");RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM).addPart(Headers.of("Content-Disposition", "form-data; name=\"username\""), RequestBody.create(null, "张鸿洋")) .addPart(Headers.of( "Content-Disposition", "form-data; name=\"mFile\"; filename=\"wjd.mp4\""), fileBody) .build(); Request request = new Request.Builder() .url("http://192.168.1.103:8080/okHttpServer/fileUpload") .post(requestBody) .build(); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { //... });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上述代码向服务器传递了一个键值对username:张鸿洋和一个文件。我们通过MultipartBuilder的addPart方法可以添加键值对或者文件。

其实类似于我们拼接模拟浏览器行为的方式,如果你对这块不了解,可以参考:从原理角度解析Android (Java) http 文件上传

ok,对于我们最开始的目录还剩下图片下载,文件下载;这两个一个是通过回调的Response拿到byte[]然后decode成图片;文件下载,就是拿到inputStream做写文件操作,我们这里就不赘述了。

关于用法,也可以参考泡网OkHttp使用教程

接下来我们主要看如何封装上述的代码。


三、封装

由于按照上述的代码,写多个请求肯定包含大量的重复代码,所以我希望封装后的代码调用是这样的:

(一)使用

  1. 一般的get请求

     OkHttpClientManager.getAsyn("https://www.baidu.com", new OkHttpClientManager.ResultCallback<String>(){@Overridepublic void onError(Request request, Exception e) { e.printStackTrace(); } @Override public void onResponse(String u) { mTv.setText(u);//注意这里是UI线程 } });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对于一般的请求,我们希望给个url,然后CallBack里面直接操作控件。

  2. 文件上传且携带参数

    我们希望提供一个方法,传入url,params,file,callback即可。

      OkHttpClientManager.postAsyn("http://192.168.1.103:8080/okHttpServer/fileUpload",//new OkHttpClientManager.ResultCallback<String>(){@Overridepublic void onError(Request request, IOException e) { e.printStackTrace(); } @Override public void onResponse(String result) { } },// file,// "mFile",// new OkHttpClientManager.Param[]{ new OkHttpClientManager.Param("username", "zhy"), new OkHttpClientManager.Param("password", "123")} ); 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    键值对没什么说的,参数3为file,参数4为file对应的name,这个name不是文件的名字; 
    对应于http中的

    <input type="file" name="mFile" >

    对应的是name后面的值,即mFile.

  3. 文件下载

    对于文件下载,提供url,目标dir,callback即可。

    OkHttpClientManager.downloadAsyn("http://192.168.1.103:8080/okHttpServer/files/messenger_01.png",    Environment.getExternalStorageDirectory().getAbsolutePath(), 
    new OkHttpClientManager.ResultCallback<String>(){@Overridepublic void onError(Request request, IOException e) { } @Override public void onResponse(String response) { //文件下载成功,这里回调的reponse为文件的absolutePath } });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  4. 展示图片

    展示图片,我们希望提供一个url和一个imageview,如果下载成功,直接帮我们设置上即可。

     OkHttpClientManager.displayImage(mImageView, "http://images.csdn.net/20150817/1.jpg");
    • 1
    • 2
    • 1
    • 2

    内部会自动根据imageview的大小自动对图片进行合适的压缩。虽然,这里可能不适合一次性加载大量图片的场景,但是对于app中偶尔有几个图片的加载,还是可用的。


四、整合Gson

很多人提出项目中使用时,服务端返回的是Json字符串,希望客户端回调可以直接拿到对象,于是整合进入了Gson,完善该功能。

(一)直接回调对象

例如现在有个User实体类:

package com.zhy.utils.http.okhttp;public class User { public String username ; public String password ; public User() { // TODO Auto-generated constructor stub } public User(String username, String password) { this.username = username; this.password = password; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

服务端返回:

{"username":"zhy","password":"123"}
  • 1
  • 1

客户端可以如下方式调用:

 OkHttpClientManager.getAsyn("http://192.168.56.1:8080/okHttpServer/user!getUser",
new OkHttpClientManager.ResultCallback<User>()
{@Overridepublic void onError(Request request, Exception e) { e.printStackTrace(); } @Override public void onResponse(User user) { mTv.setText(u.toString());//UI线程 } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我们传入泛型User,在onResponse里面直接回调User对象。 
这里特别要注意的事,如果在json字符串->实体对象过程中发生错误,程序不会崩溃,onError方法会被回调。

注意:这里做了少许的更新,接口命名从StringCallback修改为ResultCallback。接口中的onFailure方法修改为onError

(二) 回调对象集合

依然是上述的User类,服务端返回

[{"username":"zhy","password":"123"},{"username":"lmj","password":"12345"}]
  • 1
  • 1

则客户端可以如下调用:

OkHttpClientManager.getAsyn("http://192.168.56.1:8080/okHttpServer/user!getUsers",
new OkHttpClientManager.ResultCallback<List<User>>()
{@Overridepublic void onError(Request request, Exception e) { e.printStackTrace(); } @Override public void onResponse(List<User> us) { Log.e("TAG", us.size() + ""); mTv.setText(us.get(1).toString()); } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

唯一的区别,就是泛型变为List<User> ,ok , 如果发现bug或者有任何意见欢迎留言。


源码

ok,基本介绍完了,对于封装的代码其实也很简单,我就直接贴出来了,因为也没什么好介绍的,如果你看完上面的用法,肯定可以看懂:

package com.zhy.utils.http.okhttp;import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper; import android.widget.ImageView; import com.google.gson.Gson; import com.google.gson.internal.$Gson$Types; import com.squareup.okhttp.Call; import com.squareup.okhttp.Callback; import com.squareup.okhttp.FormEncodingBuilder; import com.squareup.okhttp.Headers; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.MultipartBuilder; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.net.CookieManager; import java.net.CookiePolicy; import java.net.FileNameMap; import java.net.URLConnection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Created by zhy on 15/8/17. */ public class OkHttpClientManager { private static OkHttpClientManager mInstance; private OkHttpClient mOkHttpClient; private Handler mDelivery; private Gson mGson; private static final String TAG = "OkHttpClientManager"; private OkHttpClientManager() { mOkHttpClient = new OkHttpClient(); //cookie enabled mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER)); mDelivery = new Handler(Looper.getMainLooper()); mGson = new Gson(); } public static OkHttpClientManager getInstance() { if (mInstance == null) { synchronized (OkHttpClientManager.class) { if (mInstance == null) { mInstance = new OkHttpClientManager(); } } } return mInstance; } /** * 同步的Get请求 * * @param url * @return Response */ private Response _getAsyn(String url) throws IOException { final Request request = new Request.Builder() .url(url) .build(); Call call = mOkHttpClient.newCall(request); Response execute = call.execute(); return execute; } /** * 同步的Get请求 * * @param url * @return 字符串 */ private String _getAsString(String url) throws IOException { Response execute = _getAsyn(url); return execute.body().string(); } /** * 异步的get请求 * * @param url * @param callback */ private void _getAsyn(String url, final ResultCallback callback) { final Request request = new Request.Builder() .url(url) .build(); deliveryResult(callback, request); } /** * 同步的Post请求 * * @param url * @param params post的参数 * @return */ private Response _post(String url, Param... params) throws IOException { Request request = buildPostRequest(url, params); Response response = mOkHttpClient.newCall(request).execute(); return response; } /** * 同步的Post请求 * * @param url * @param params post的参数 * @return 字符串 */ private String _postAsString(String url, Param... params) throws IOException { Response response = _post(url, params); return response.body().string(); } /** * 异步的post请求 * * @param url * @param callback * @param params */ private void _postAsyn(String url, final ResultCallback callback, Param... params) { Request request = buildPostRequest(url, params); deliveryResult(callback, request); } /** * 异步的post请求 * * @param url * @param callback * @param params */ private void _postAsyn(String url, final ResultCallback callback, Map<String, String> params) { Param[] paramsArr = map2Params(params); Request request = buildPostRequest(url, paramsArr); deliveryResult(callback, request); } /** * 同步基于post的文件上传 * * @param params * @return */ private Response _post(String url, File[] files, String[] fileKeys, Param... params) throws IOException { Request request = buildMultipartFormRequest(url, files, fileKeys, params); return mOkHttpClient.newCall(request).execute(); } private Response _post(String url, File file, String fileKey) throws IOException { Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null); return mOkHttpClient.newCall(request).execute(); } private Response _post(String url, File file, String fileKey, Param... params) throws IOException { Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params); return mOkHttpClient.newCall(request).execute(); } /** * 异步基于post的文件上传 * * @param url * @param callback * @param files * @param fileKeys * @throws IOException */ private void _postAsyn(String url, ResultCallback callback, File[] files, String[] fileKeys, Param... params) throws IOException { Request request = buildMultipartFormRequest(url, files, fileKeys, params); deliveryResult(callback, request); } /** * 异步基于post的文件上传,单文件不带参数上传 * * @param url * @param callback * @param file * @param fileKey * @throws IOException */ private void _postAsyn(String url, ResultCallback callback, File file, String fileKey) throws IOException { Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null); deliveryResult(callback, request); } /** * 异步基于post的文件上传,单文件且携带其他form参数上传 * * @param url * @param callback * @param file * @param fileKey * @param params * @throws IOException */ private void _postAsyn(String url, ResultCallback callback, File file, String fileKey, Param... params) throws IOException { Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params); deliveryResult(callback, request); } /** * 异步下载文件 * * @param url * @param destFileDir 本地文件存储的文件夹 * @param callback */ private void _downloadAsyn(final String url, final String destFileDir, final ResultCallback callback) { final Request request = new Request.Builder() .url(url) .build(); final Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(final Request request, final IOException e) { sendFailedStringCallback(request, e, callback); } @Override public void onResponse(Response response) { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; try { is = response.body().byteStream(); File file = new File(destFileDir, getFileName(url)); fos = new FileOutputStream(file); while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); } fos.flush(); //如果下载文件成功,第一个参数为文件的绝对路径 sendSuccessResultCallback(file.getAbsolutePath(), callback); } catch (IOException e) { sendFailedStringCallback(response.request(), e, callback); } finally { try { if (is != null) is.close(); } catch (IOException e) { } try { if (fos != null) fos.close(); } catch (IOException e) { } } } }); } private String getFileName(String path) { int separatorIndex = path.lastIndexOf("/"); return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length()); } /** * 加载图片 * * @param view * @param url * @throws IOException */ private void _displayImage(final ImageView view, final String url, final 

转载于:https://www.cnblogs.com/xgjblog/p/6007052.html

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

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

相关文章

c盘users的用户名怎么改_做完这几个操作,我从C盘中清理了30G垃圾文件

信息技术土著&#xff0c;一个有营养的公众号有个存在学说&#xff0c;比说一个人的身体某部位&#xff0c;如果不痛&#xff0c;你很少感觉他是存在的&#xff0c;但是某一天&#xff0c;因为某种原因&#xff0c;它突然很痛了&#xff0c;然后你每时每刻都会感觉到它的存在了…

MongoDB在Linux下常用优化设置

MongoDB在Linux下常用优化设置以下是一些MongoDB推荐的常用优化设置。在生产环境下选取合适的参数值&#xff0c;例如预读值和默认文件描述符数目等&#xff0c;会对系统性能有很大的影响。1、关闭数据库文件的 atime禁止系统对文件的访问时间更新会有效提高文件读取的性能。这…

ipconfig没有显示ip_TCP/IP 协议修复网络问题

nternet 在 TCP/IP 协议上工作&#xff0c;如果 TCP/IP 协议堆栈在 Windows 或任何其他操作系统(例如 Linux 或 MacOS)中无法正常工作&#xff0c;则您的 Internet 连接会出现问题。解决 Internet 问题的最佳方法是重置 TCP/IP 堆栈设置。如何在 Windows 中重置 TCP/IP 堆栈&am…

mysql-linux64,Linux64下mysql安装和开辟

1.1地址&#xff1a;http://www.mysql.com/downloads/mysql/5.5.html&#xff03;downloads版本&#xff1a;5.1.68平台&#xff1a;linux generalGeneric Linux (glibc 2.3) (x86&#xff0c; 64-bit)&#xff0c; RPM Package版本&#xff1a;MySQL Server(MySQL-server-5.1.…

python截图识别文字_用百度ocr+微信截图实现文字识别

作用&#xff1a;将图片中的文字识别出来 一、调用微信截图dll控件 将微信截图插件复制到项目文件&#xff0c;使用ctypes加载&#xff08;胶水语言就是给力&#xff09; def capture(): try: dll ctypes.cdll.LoadLibrary(PrScrn.dll) except Exception: print("Dll loa…

【用jQuery来判断浏览器的类型】及【javascript获取用户ip地址】

用jQuery来判断浏览器的类型,主要是使用$.browser这个工具类,使用方法: $.browser.[浏览器关键字] //谷歌浏览器、360浏览器等其他一些浏览器&#xff0c;没有专门的判断 function appInfo() {var bro $.browser;var binfo "";if (bro.msie) {binfo "Micr…

linux mv 递归拷贝,奇技淫巧 - 给Linux中的cp和mv命令中添加进度条的高级拷贝

GNU cp和GNU mv命令用于在GNU/Linux操作系统中复制和移动文件和目录。这两个命令缺少的一个特性是它们不显示任何进度条。如果复制一个大文件或目录&#xff0c;您就不知道完成复制过程需要多长时间&#xff0c;也不知道复制的数据所占的百分比。还有您将看不到当前正在复制哪个…

【洛谷P1966】火柴排队

两列排序后将编号一一对应 归并排序求逆序对 &#xff08;每一次交换就去掉一个逆序对&#xff09; 1 #include<cstdio>2 #include<cstring>3 #include<algorithm>4 #define ll long long5 using namespace std;6 const int N100100;7 const ll P99999997;8 …

Alan Walker MV 合辑01 by defender

Alan Walker MV合辑 出来啦&#xff01; 百度网盘下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/10WSool70XBe_8tJOae8V-w 提取码&#xff1a;uckq 地址查看Microsoft Onedrive Download Address:  BE DELETED Google Drive Download Address&#xff1a; …

在unity中设置多种怪物数据_Unity可编程渲染管线(SRP)系列(三)——光照(单通道 正向渲染)...

本文重点:1、漫反射着色2、支持方向光、点光源和聚光灯3、每帧允许16个可见光源4、每个对象最多计算四个像素光和四个顶点光这是涵盖Unity可编写脚本的渲染管线的教程系列的第三部分。这次&#xff0c;我们将通过一个Drawcall为每个对象最多着色8个灯光来增加对漫反射光照的支持…

蛋清打发奶油状

在做蛋糕、冰淇凌、面包之类的时候往往都需要奶油状蛋清&#xff0c;让蛋糕、面包更蓬松&#xff0c;冰激凌也可以使用其当做奶油来用。用料 鸡蛋4个 根据用量选择盐(只做冰激凌用奶油放)5g(根据蛋量)白醋(可以不放&#xff0c;根据喜好)5g(根据蛋量)白砂糖40g(分三次放)根据…

hql可以使用distinct吗_输送食品可以使用白色PVC输送带吗?

食品&#xff0c;是给人们吃到肚子里的&#xff0c;因此不管在加工环节、制造环节还是其他环节&#xff0c;都需要做好食品的安全问题。根据不同的食品&#xff0c;其制造的环境也不同&#xff0c;所使用到的食品输送带的材质也是不一样的&#xff0c;这些是需要根据输送的食品…

htc one m7 linux驱动,HTC One M7官方RUU固件包(可救砖)

在网上找了找关于HTC One M7 (801e)的官方ruu固件包还不多&#xff0c;找了一些&#xff0c;不过有些不能下载&#xff0c;在这里整理了几款可以下载的官方ruu包&#xff0c;这些包都是官方原版的&#xff0c;都是支持线刷的&#xff0c;大家可以下载下来备用了&#xff0c;也可…

c语言fmin最小公倍数,matlab小函数

8种机械键盘轴体对比本人程序员&#xff0c;要买一个写代码的键盘&#xff0c;请问红轴和茶轴怎么选&#xff1f;(记得按字母序索引)矩阵向量化操作A(:)拉成一个向量 ($a_{11},a_{21},…$)&#xff0c;注意先列后行repmat用途&#xff1a;创建由小型矩阵重复组合成的矩阵&#…

报表系统的雄心

这周有朋自远方来&#xff0c;聊了对报表工具的看法&#xff0c;因此专门写篇文章来谈谈报表系统的未来。 笔者知道不可能有十全十美的报表系统&#xff0c;毕竟任何一个行业和企业受自身客观环境的限制&#xff0c;但表哥嘛&#xff0c;总要有点理想和追求&#xff0c;就好比到…

vuefullcalendar怎么判断切换上下月_房间太多、楼上楼下,终极解决家里wifi信号无缝切换问题...

相信不少人有我一样的烦恼&#xff0c;房间太多&#xff0c;或者楼上楼下&#xff0c;家里的wifi信号总是不能无缝切换。路由器放在配电箱&#xff0c;除了客厅信号不错外&#xff0c;一旦到了其他房间&#xff0c;掉线、网速慢等问题让人很苦恼。特别是和小伙伴一起玩游戏一边…

手把手教你 Spark 性能调优

0、背景 集群部分 spark 任务执行很慢&#xff0c;且经常出错&#xff0c;参数改来改去怎么都无法优化其性能和解决频繁随机报错的问题。 看了下任务的历史运行情况&#xff0c;平均时间 3h 左右&#xff0c;而且极其不稳定&#xff0c;偶尔还会报错&#xff1a; 1、优化思路 任…

pytorch线性回归代码_[PyTorch 学习笔记] 1.3 张量操作与线性回归

本章代码&#xff1a;https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson1/linear_regression.py张量的操作拼接torch.cat()torch.cat(tensors, dim0, outNone)功能&#xff1a;将张量按照 dim 维度进行拼接tensors: 张量序列dim: 要拼接的维度代码示例&#…

《UNIXLinux程序设计教程》一2.1 UNIX 输入输出基本概念

2.1 UNIX 输入输出基本概念 在任何一种操作系统中&#xff0c;程序开始读写一个文件的内容之前&#xff0c;必须首先在程序与文件之间建立连接或通信通道&#xff0c;这一过程称为打开文件。打开一个文件的目的可能是要读其中的数据&#xff0c;也可能是要往其中写入数据&…

c语言编常见算法,5个常见C语言算法

5个常见C语言算法十进制转换为二进制的递归程序字符串逆置的递归程序整数数位反序&#xff0c;例如12345->54321四舍五入程序(考虑正负数)二分法查找的递归函数#include#include#include//十进制转换为二进制的递归程序voidDecimalToBinary(int n){if(n<0){printf("…