1.HTTP报文Header中Host
不是在网络上用于寻址的,而是在目标服务器上用于定位子服务器的.
2.对称加密
1个密钥+2个算法(加密算法,解密算法)
明文-->(密钥+加密算法)-->密文
密文-->(密钥+解密算法)-->明文
3.非对称加密
2个密钥(公钥+私钥)+1个加密算法
A发送数据给B:
A:明文-->(B的公钥+加密算法)-->密文 ==> B:(B的私钥+加密算法)-->明文
非对称加密:公钥和私钥互相可解.公钥发给对方,私钥自己保管.
4.编码
把数据从一种数据形式转换为另一种数据形式,如Base64.
编码一定有解码与之对应.
5.Http确认授权的2种方式
1.通过Cokkie
2.通过Header中添加Authorization
Authorization两种主流方式:Basic , Bearer
Authorization: Basic username:password执行Base64编码的字符串
如:Authorization: Basic 12345678
Authorization: Bearer bearer token
bearer token 需要通过 OAuth2的授权流程获取.
- 第三方网站向授权方网站申请第三方授权合作,拿到client id和client secret.client secret需要绝对保密,一直存在第三方网站服务器.
- 用户使用掘金,点击GitHub登录,首先跳转到GitHub网站,并将client id传入.
- GitHub根据client id,将掘金信息及掘金需要的GitHub用户的权限进行展示,询问用户是否同意
- 用户点击'同意',GitHub重新跳转回掘金,并传入Authorization code作为用户同意凭证.
- 掘金将Authorization code发送回掘金自己服务器
- 掘金服务器将Authorization code及client secret一并发送给GitHub服务器(这个连接一定是HTTPS连接,是绝对安全的),GitHub验证通过,则返回access token/bearer token.
- 掘金获取到access token,就向GitHub发送请求,用于获取该用户的信息/操作用户账户.
6.Https证书验证
比如A想访问B网站,B网站的证书是BA;
A在在发送请求路程中间,被C网站截获,C网站将自己的证书CA返回给A.
CA本身也是一个合法的证书,A怎么去辨认?
通过证书信息中的域名(host)去辨认.比如A要访问alibaba,结果被tencent截获,返回了tencent的证书,虽然tencent证书本身合法,但是tencent的证书信息中,host是tencent,不是alibaba,和A要访问的域名不一致,就不会进行后续的验证工作.
证书不能伪造,也不能篡改.因为证书签发机构的私钥第三方是拿不到的,改了任何信息,都会导致修改后信息的HASH和证书签名被签发机构公钥运算后的结果对不上,导致认证失败!
7.Retrofit
- 常见使用方法
public class Student{ **** } public interface StudentService{ @GET("students/{gender}") Call<List<Student>> gainStudents(@Path("gender") String gengderValue); } Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://services.students.com/") .build(); StudentService service = retrofit.create(StudentService.class); Call<List<Student>> students = service.gainStudents("男"); students.enqueue(new Callback<List<Student>>(){ @Override public void onResponse(Call<List<Student>> call, Response<List<Student>> response) { } @Override public void onFailure(Call<List<Student>> call, Throwable t) { } }); - Retrofit.create(Class)创建出Service接口实例,是Retrofit代码结构的核心.
retrofit-2.7.1-sources.jar!\retrofit2\Retrofit.java public <T> T create(final Class<T> service) { validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[]{service }, new InvocationHandler() { private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0]; @Override public @Nullable Object invoke(Object proxy, Method method,@Nullable Object[] args) throws Throwable { //如果method是Object中声明的方法,则改写,直接返回调用结果. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); } }); } retrofit-2.7.1-sources.jar!\retrofit2\Platform.java class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get() { return PLATFORM; } private static Platform findPlatform() { try { Class.forName("android.os.Build"); if (Build.VERSION.SDK_INT != 0) { //对于Android平台而言,一定返回new Android() return new Android(); } } catch (ClassNotFoundException ignored) { } return new Platform(true); } private final boolean hasJava8Types; Platform(boolean hasJava8Types) { this.hasJava8Types = hasJava8Types; } boolean isDefaultMethod(Method method) { return hasJava8Types && method.isDefault(); } static final class Android extends Platform { Android() { //当Android sdk版本>=24,则hasJava8Types为true super(Build.VERSION.SDK_INT >= 24); } @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } } } Sdk\sources\android-29\java\lang\reflect\Method.java public boolean isDefault() { // Android-changed: isDefault() implemented using Executable. return super.isDefaultMethodInternal(); } - Retrofit执行网络请求调用顺序
- create 利用动态代理,在运行时创建Service/网络请求接口具体事例
- 调用Service中具体方法,实质是执行InvocationHandler的invoke方法
- return loadServiceMethod(method).invoke
- loadServiceMethod->ServiceMethod.parseAnnotations
- parseAnnotations:SuspendForBody
Annotation[] annotations = method.getAnnotations(); //获取 适配器 CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit,method, adapterType, annotations); Type responseType = callAdapter.responseType(); //获取 转换器 Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); - createCallAdapter(retrofit,method, adapterType, annotations);
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) { return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, } public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } //可见,最终返回值是callAdapterFactories中的一个item创建的CallAdapter实例 public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { int start = callAdapterFactories.indexOf(skipPast) + 1; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } } Retrofit: private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); public Retrofit build() { List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor)); } Platform.java List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) { //可见,Retrofit默认配置了1个或2个CallAdapter.Factory //DefaultCallAdapterFactory 或 DefaultCallAdapterFactory+CompletableFutureCallAdapterFactory DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor); return hasJava8Types ? asList(CompletableFutureCallAdapterFactory.INSTANCE,executorFactory) : singletonList(executorFactory); } CompletableFutureCallAdapterFactory.java: @Override public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != CompletableFuture.class) { //返回类型不是CompletableFuture,则返回null return null; } **** } DefaultCallAdapterFactory.java: @Override public @Nullable CallAdapter<?, ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { //返回类型不是retrofit2.Call,则返回null if (getRawType(returnType) != Call.class) { return null; } //返回类型不是泛型类型,则返回null if (!(returnType instanceof ParameterizedType)) { throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>"); } }- 默认情况下,Service接口中方法返回类型都是Call,属于泛型类型.推断出nextCallAdapter返回值为DefaultCallAdapterFactory实例执行get方法获得的CallAdapter实例.
- createResponseConverter
Type responseType = callAdapter.responseType(); //获取 转换器 Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter( Retrofit retrofit, Method method, Type responseType) { Annotation[] annotations = method.getAnnotations(); return retrofit.responseBodyConverter(responseType, annotations); } Retrofit.java public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) { return nextResponseBodyConverter(null, type, annotations); } public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { int start = converterFactories.indexOf(skipPast) + 1; //返回的是 converterFactories 中的1个实例创建的 转换器实例/Converter for (int i = start, count = converterFactories.size(); i < count; i++) { Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { return (Converter<ResponseBody, T>) converter; } } } final List<Converter.Factory> converterFactories; public Retrofit build() { converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this.converterFactories); converterFactories.addAll(platform.defaultConverterFactories()); }- Retrofit默认添加的Converter,是不能直接将响应转换为我们需要的特定类型的,如List等.
- invoke:
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); 上面创建了SuspendForBody,看SuspendForBody的adapt方法. @Override protected Object adapt(Call<ResponseT> call, Object[] args) { call = callAdapter.adapt(call); Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1]; try { return isNullable ? KotlinExtensions.awaitNullable(call, continuation) : KotlinExtensions.await(call, continuation); } catch (Exception e) { return KotlinExtensions.suspendAndThrow(e, continuation); } } //所以adapt方法返回的还是retrofit2.Call实例 public suspend fun <T : kotlin.Any> retrofit2.Call<T>.await(): T { /* compiled code */ } - 即create创建Service实例,调用其指定方法,返回retrofit2.Call对象.
- retrofit2.Call实例调用enqueue方法,实际是调用其实现类OkHttpCall实例的enqueue.
@Override public void enqueue(final Callback<T> callback) { okhttp3.Call call; call = rawCall; //call实际是okhttp3.Call实例 call = rawCall = createRawCall(); call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response = parseResponse(rawResponse); callback.onResponse(OkHttpCall.this, response); } @Override public void onFailure(okhttp3.Call call, IOException e) { callback.onFailure(OkHttpCall.this, e); } }); } //使用callFactory创建okhttp3.Call实例 private okhttp3.Call createRawCall() throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; } - 总结:利用create方法,在运行时生成Service具体实例,调用指定网络接口,实际执行InvocationHandler的invoke方法,进而生成retrofit2.Call call实例返回.调用call的enque方法,实际是调用okhttp3.Call实例的enque执行真正网络请求逻辑.
8.Retrofit源码解析
9.OkHttp
- OkHttpClient.java
- final CertificatePinner certificatePinner :
- 可用于证书自签名
- 防止网站证书被Hack:例如自身网站证书签发A的机构被收买,给别人签了我们网站的证书B.由于B本身是合法的,所以B正常流程下是可以通过证书校验的.而我们App使用CertificatePinner,就可以将我们网站所有证书公钥写死,不再使用本地根证书验证.防止B通过验证.
- final Authenticator authenticator:
- 用于自动重新认证.配置后,在收到401后,会直接调用authenticator,加入配置过的Header->Authorization后自动重新发起请求.
OkHttpClient okHttpClient = new OkHttpClient.Builder() .authenticator(new Authenticator() { @Nullable @Override public Request authenticate(@Nullable Route route, okhttp3.Response response) throws IOException { //假设是Bearer方式,首先通过OAuth2流程获取到bearer token String bearer_token = "1111111111"; return response .request() .newBuilder() //然后将Authorization配置上去 .addHeader("Authorization","Bearer " + bearer_token) .build(); } }) .build();
- final CertificatePinner certificatePinner :
- addInterceptor 和 addNetworkInterceptor.
addInterceptor示例: Interceptor interceptor = new Interceptor() { @Override public okhttp3.Response intercept(Chain chain) throws IOException { //对请求做前置工作 Request request = chain.request(); request = request.newBuilder().addHeader("name","value").build(); //获取响应数据 okhttp3.Response response = chain.proceed(request); //对响应做后置工作 response = response.newBuilder().addHeader("anotherName","anotherValue").build(); return response; } }; OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(interceptor) .build();- 通过 addInterceptor() 方法添加的拦截器是放在最前面的.通过addNetworkInterceptor() 方法添加的网络拦截器,则是在非 WebSocket 请求时,添加在 ConnectInterceptor 和 CallServerInterceptor 之间的.
addInterceptor(应用拦截器): 1,不需要担心中间过程的响应,如重定向和重试. 2,总是只调用一次,即使HTTP响应是从缓存中获取. 3,观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match. 4,允许短路而不调用 Chain.proceed(),即中止调用. 5,允许重试,使 Chain.proceed()调用多次. addNetworkInterceptor(网络拦截器): 1,能够操作中间过程的响应,如重定向和重试. 2,当网络短路而返回缓存响应时不被调用. 3,只观察在网络上传输的数据. 4,携带请求来访问连接.
- 通过 addInterceptor() 方法添加的拦截器是放在最前面的.通过addNetworkInterceptor() 方法添加的网络拦截器,则是在非 WebSocket 请求时,添加在 ConnectInterceptor 和 CallServerInterceptor 之间的.
- getResponseWithInterceptorChain
Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); //先添加通过 OkHttpClient.Builder # addInterceptor() 方法添加的拦截器 interceptors.addAll(client.interceptors()); interceptors.add(new RetryAndFollowUpInterceptor(client)); interceptors.add(new BridgeInterceptor(client.cookieJar())); interceptors.add(new CacheInterceptor(client.internalCache())); interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { //如果不是 WebSocket 请求,则添加通过 OkHttpClient.Builder # addNetworkInterceptor() 方法添加的拦截器 interceptors.addAll(client.networkInterceptors()); } //最终是在CallServerInterceptor中执行真正网络请求,及响应获取 interceptors.add(new CallServerInterceptor(forWebSocket)); //构建拦截器链 Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0, originalRequest, this, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis()); boolean calledNoMoreExchanges = false; try { //链式调用,类似递归,获得网络请求的响应数据 Response response = chain.proceed(originalRequest); if (transmitter.isCanceled()) { closeQuietly(response); throw new IOException("Canceled"); } return response; } catch (IOException e) { calledNoMoreExchanges = true; throw transmitter.noMoreExchanges(e); } finally { if (!calledNoMoreExchanges) { transmitter.noMoreExchanges(null); } } }
10.自定义View
- onSizeChanged
- 在layout方法之中调用.layout中发现View的尺寸发生改变才会调用.如果尺寸没有变化,即使layout调用多次也不会重复调用onSizeChanged
This is called during layout when the size of this view has changed. 在控件大小发生改变时调用 protected void onSizeChanged(int w, int h, int oldw, int oldh) { }
- 在layout方法之中调用.layout中发现View的尺寸发生改变才会调用.如果尺寸没有变化,即使layout调用多次也不会重复调用onSizeChanged
- Path.setFillType
- Path.setFillType(fillType) 是⽤用来设置图形⾃自相交时的填充算法
- FillType.EVEN_ODD 特别适合做Path的镂空效果.
public void setFillType(@NonNull FillType ft) { **** }
- PathMeasure可以测量Path的长度;
- PathDashPathEffect 可用于绘制类似仪表盘刻度.
- Paint的setXfermode可以实现类似圆形图片效果.
要和离屏缓冲共同使用才有效. - Math.toRadians(double angdeg) :角度转弧度
角度转弧度,用于后续sin,cos计算. - 示例
public class DashboardView extends View { private Paint paint; private float angle = 270; private int segments = 20; private float markWidth = 4; private int markLength = 20; private int pointerLength = 150; private float radius = 200; private float lineWidth = 4; private PathDashPathEffect pathDashPathEffect = null; RectF rectF = null; float startAngele = 0F; **** @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); float left = getWidth()/2 - radius; float right = getWidth()/2 + radius; float top = getHeight()/2 - radius; float bottom = getHeight()/2 + radius; rectF = new RectF(left,top,right,bottom); startAngele = 90 + (360 - angle) / 2; Path mark = new Path(); mark.addRect(0,0,markWidth,markLength, Path.Direction.CCW); Path arc = new Path(); arc.addArc(rectF,startAngele,angle); //PathMeasure 测量Path长度 PathMeasure pathMeasure = new PathMeasure(arc,false); float arcLength = pathMeasure.getLength(); float advance = (arcLength - markWidth) / segments; pathDashPathEffect = new PathDashPathEffect(mark,advance,0, PathDashPathEffect.Style.ROTATE); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setColor(Color.BLACK); //绘制仪表盘外围圆弧 canvas.drawArc(rectF,startAngele,angle,false,paint); //设置路径效果 paint.setPathEffect(pathDashPathEffect); //绘制刻度 canvas.drawArc(rectF,startAngele,angle,false,paint); paint.setPathEffect(null); //绘制指针 float centerX = getWidth() / 2; float centerY = getHeight() / 2; float endX = (float) (centerX + pointerLength * Math.cos(Math.toRadians(startAngele))); float endY = (float) (centerY + pointerLength * Math.sin(Math.toRadians(startAngele))); paint.setColor(Color.BLUE); canvas.drawLine(centerX,centerY,endX,endY,paint); } } public class XfermodeView extends View { **** private void init() { //获取Bitmap实例 bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.img_head); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float centerX = getWidth() / 2; float centerY = centerX; //离屏缓冲步骤 //1:canvas.saveLayer.将要使用离屏缓冲的范围抠出来 int saveId = canvas.saveLayer(0,0,getWidth(),getHeight(),paint); //2:绘制DST paint.setColor(Color.RED); canvas.drawCircle(centerX,centerY,centerX,paint); //3:setXfermode(指定Mode) paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); //4:绘制SRC canvas.drawBitmap(bitmap,0,0,paint); //5:setXfermode(null) paint.setXfermode(null); //6:恢复Canvas canvas.restoreToCount(saveId); } } public class PieView extends View { **** private int selectedIndex = 2; private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private float centerX,centerY,radius; private RectF rectF; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); centerX = getWidth() / 2; centerY = getHeight() / 2; radius = Math.min(centerX,centerY) - 50; rectF = new RectF(centerX - radius,centerY-radius,centerX+radius,centerY+radius); paint.setStyle(Paint.Style.FILL); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //要画几块扇形 int segments = Math.min(colors.length,angles.length); //当前起始角度 float currentAngle = 0F; for(int i = 0; i < segments; i++){ if(i == selectedIndex){ //要'选中'的部分 float angle = currentAngle + angles[i] / 2; float dx = (float) (30 * Math.cos(Math.toRadians(angle))); float dy = (float) (30 * Math.sin(Math.toRadians(angle))); //canvas执行平移 //先save int saveId = canvas.save(); //平移 canvas.translate(dx,dy); //绘制扇形 canvas.drawArc(rectF,currentAngle,angles[i],true,paint); //再restoreToCount canvas.restoreToCount(saveId); currentAngle += angles[i]; }else{ //绘制扇形 paint.setColor(colors[i]); canvas.drawArc(rectF,currentAngle,angles[i],true,paint); currentAngle += angles[i]; } } } } - Canvas.clip***
- 绘制一定会出现锯齿的,不可能解决.这不属于BUG.如果要画圆形图片,使用paint.setXfermode实现.
Paint.setAntiAlias(boolean aa)来动态开关抗锯⻮齿.
⽑毛边或者锯⻮齿,发⽣生的原因并不不是很多⼈人所想象的「绘制太粗糙」「像素计算能⼒力力不不⾜足」;同样,抗锯⻮齿的原理理也并不不是选择了了更更精细的算法来算出了了更更平滑的图形边缘。实质上,锯⻮齿现象的发⽣生,只是由于图形分辨率过低,导致⼈人眼察觉出了了画⾯面中的像素颗粒⽽而已。换句句话说,就算不不开启抗锯⻮齿,图形的边缘也已经是最完美的了了,⽽而并不不是⼀一个粗略略计算的粗糙版本。
那么,为什什么抗锯⻮齿开启之后的图形边缘会更更加平滑呢?因为抗锯⻮齿的原理理是:修改图形边缘处的像素颜⾊色,从⽽而让图形在⾁肉眼看来具有更更加平滑感觉. 未开启抗锯⻮齿的圆,所有像素都是同样的⿊黑⾊色,⽽而开启了了抗锯⻮齿的圆,边缘的颜⾊色被略略微改变了了。这种改变可以让⼈人眼有边缘平滑的感觉,但从某种⻆角度讲,它也造成了了图形的颜⾊色失真。
而Canvas.clip***是直接对绘制的内容直接作了裁切,不存在修改图形边缘像素颜色的动作.所以对于圆形等图形,分辨率过低就一定会出现锯齿.只能使用XfermodeView方式解决.
www.jianshu.com/p/8b3c4af98…
stackoverflow.com/questions/2…
- 绘制一定会出现锯齿的,不可能解决.这不属于BUG.如果要画圆形图片,使用paint.setXfermode实现.