Android 面试点
###测试请求的地址
> `http://httpbin.org`
###post上传数据的数据形式
* key-value:-->表单.结构单一.而且繁琐
List<BasicNameValuePair> parameters = new ArrayList<BasicNameValuePair>();
for (Map.Entry<String, String> info : map.entrySet()) {
String name = info.getKey();
String value = info.getValue();
BasicNameValuePair basicNameValuePair = new BasicNameValuePair(name, value);
parameters.add(basicNameValuePair);
}
UrlEncodedFormEntity postEntity = new UrlEncodedFormEntity(parameters);
post.setEntity(postEntity);
* jsonString:结果灵活.市面上基本就是用这样的形式;
//这个养成良好习惯.一定要记得加上.实际开发因为这个请求头.出了很多次问题
post.addHeader("Content-Type", "application/json");
//设置post的数据 key-value
post.setEntity(new StringEntity(jsonString));
* file:使用httpmime-4.3.jar+httpclient
* 单张图片:
* 多张图片:
//单张图片
/*MultipartEntity entity = new MultipartEntity();
ContentBody contentBody = new FileBody(file);
entity.addPart("actimg", contentBody);
post.setEntity(entity);*/
//多张图片
MultipartEntity postEntity = new MultipartEntity();
for (Map.Entry<String, File> info : fileMap.entrySet()) {
String key = info.getKey();
File file = info.getValue();
ContentBody contentBody = new FileBody(file);
postEntity.addPart(key, contentBody);//其实多张图片就是多次addPart
}
post.setEntity(postEntity);
###常见的content-type
* application/x-www-form-urlencoded:表单,key-value
* multipart/form-data:二进制,file
* text/plain:普通文本,默认类型
* **application/json** :json,虽然有的服务器直接用`text/plain`这个请求头没有任何问题.但是很多服务器,必须需要`application/json`,明确的说.如果是返回json,一定加上`application/json`,不要用默认的.实际开发遇到了几次这样的问题.或者说.**加上这个请求头肯定是万无一失**;
* text/xml :xml
###模拟请求插件restClient的使用
> 这个是firefox上的一个插件,对应chrome浏览器叫做postman,这个插件主要用作和服务器开发人员联调协议;
* key-value:
* 1.添加head-->Content-Type
* 2.传递参数:key=value&key=value
* jsonString
* 1.添加head
* 2.传递参数:jsonString
###编码.数字摘要.加密.解密
* 编码:Base64,urlEncoder/urlDecoder
* urlEncoder:地址栏不允许中文,传递一些特殊字符 & ?
String url = "http://www.baidu.com?serarch=\"哈哈\"&key=value";//& ?
//URLEncoder encode
String encode = URLEncoder.encode(url);
System.out.println(encode);
//URLDecoder decode
String decode = URLDecoder.decode(encode);
System.out.println(decode);
//没有经过encode的字符串.直接decode,会原样输出
String decode2 = URLDecoder.decode(url);
System.out.println(decode2);
* Base64:把一些对象转换成string,用处:传输的时候不要明文传输
* 上传图片,上传语音
* 如何把一个map存到sp-->Base64支持把byte[]-->String,只需把对象先转换成byte[]就可以存到sp中
ImageView iv = (ImageView) findViewById(R.id.iv);
//1.得到bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
//2.bitmap-->byte[]
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 100, out);
byte[] bitmapByteArr = out.toByteArray();
//3.使用base64 byte[]--String--->上传到服务器
String bitmapBase64String = Base64.encodeToString(bitmapByteArr, Base64.DEFAULT);
//key-value jsonString
//4.String-->byte[]
byte[] bitmapByteArr2 = Base64.decode(bitmapBase64String, Base64.DEFAULT);
//5.byte[]-->Bitmap -->完成图片的上传
Bitmap bitmapPassed = BitmapFactory.decodeByteArray(bitmapByteArr2, 0, bitmapByteArr2.length);
//6.设置图片到imageView
iv.setImageBitmap(bitmapPassed);
* 数字摘要:md5 sha1
* md5:密码一般都是需要md5,不可逆,而且1kb的文件和1tb的文件.md5之后.得到的结果长度是一样;
* md5作用:或者叫做数字摘要作用-->**`确定数据未被修改`** **`文件的唯一性`**
* 加盐: 就是在密码的前面加入一些特殊字符%^&&%^&
* sha1:和md5算法不一样.作用一样
* android support v4:v4包的版本冲突.就是根据sha1值判断
* 秒传功能:其实也是根据文件的sha1
* 加密/解密
* 对称加密:只有一把`密钥`,如果密钥暴露,文件就会被暴露
* des: Data Encryption Standard
* aes: Advanced Encryption Standard
* 特点:加密速度比较快.可以加密比较大的文件
* 密码可以自己指定
* 非对称加密:有两把钥匙(`密钥对`),`公钥`和`私钥`,公钥的话给别人.私钥自己保存;
* RSA
* 特点:加密速度比慢一些,但是安全系数比较高
* 秘钥对的话需要程序生成.不能我们自己定义
* 加密/解密:公钥加密-->私钥解密
* `public static byte[] encryptByPublicKey(byte[] data, String publicKey)`//公钥加密
* `public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) `//私钥解密
* 加密/解密:私钥加密-->公钥解密
* `public static byte[] encryptByPrivateKey(byte[] data, String privateKey) `//私钥加密
* public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)//公钥解密
* 数字签名:**确定数据来源的不可否认性**,确定所属关系-->其实就是确定privatekey在哪里.
* 签名:`public static String sign(byte[] data, String privateKey)`//只能使用私钥进行签名
* 校验:`public static boolean verify(byte[] data, String publicKey, String sign) `
* 公钥互换:两个人,两个机构,就是说两个密钥对的持有者相互的置换公钥
###sqlite db文件加密
* 如果应用的数据很多是来源db文件-->核心数据
* 聊天信息-->敏感数据
* sqlitecipher
* 使用它,应用程序体积会大很多.因为需要引入差不多6m的东西
* 步骤:
* 加入libs
* 加入assets
* 注意引擎的初始化
###sqlite 数据库表字段巧设计
* 缓存bean的属性比较多-->数据库表的列字段比较--->很繁琐(代码可能需要不停的put put put)
* 项目的初期,表字段可能增加,减少,以及修改-->都会修改表结构-->所以缓存的数据就没啥用
* 解决方法,我们可以把相关的信息json化之后,保存它的jsonString就可以了
db.execSQL("CREATE TABLE `" + TABLE_NAME_CINEMA_SIMPLE + "` ( `Id` integer primary key autoincrement, "//
+ "`cityId` varchar(10)," + //
"`cinemaId` varchar(10)," + //
" `cinemaSimpleInfo` varchar(400)," + //这里就是我们jsonString
"`insertDate` varchar(10))");// /
###移动支付
> 用户使用移动的设备,完成对所购买商品或者服务的支付功能.远程支付(网上支付,短信支付),近场支付(刷卡,滴卡,pos机)
###app集成支付功能/支付功能
###常见的支付厂商
* **支付宝**:阿里公司,支付宝使用比较多.
* **微信**:腾讯公司,也是越来越多.
* 易付宝:
* 财付通:腾讯公司
* **银联**:不属于某一个公司
* 百付宝:百度
* 支付宝钱包:阿里的.
* 百度钱包:百度
* 快钱:
* **ping++**:整合了很多的支付平台
###支付难不难?
> 不难,都是属于第三方的东西.难度不大
###支付安不安全?
> 肯定是安全的.因为这些都是大公司的产品.都有自己的安全策略;
###做一个支付需要多久?
>程序员实际集成时间
* 项目评估
* 支付宝:大概5分钟.
* 银联支付:大概5分钟.
* 微信支付:大概10分钟.
###支付流程_从生活出发
1. 选择商品
2. 选择支付方式
3. 处理支付结果
1. 成功
2. 失败
3. 取消
###支付流程_从app开发角度(保证可以先完成功能)
1. 拼接支付信息,post到服务器;-->request
1. 支付信息包含支付方式
2. 服务器:是我们自己的服务器
3. 支付协议:`http://mobileif.maizuo.com/version3/orderform/order?version=2`
2. 服务器返回`支付串码`;--->reponse
请求的url(支付协议/确认订单协议): http://mobileif.maizuo.com/version3/orderform/order?version=2
请求方式:post
post参数形式:jsonString
输入参数:{"goodInfos":[{"goodCounts":"1","goodExtInfo":{},"goodIDs":"361","goodType":"1"}],"loginFlag":"0","mobile":"18682036558","orderId":"0","otherInfo":{"agentID":"0-maizuo","channelID":"31","clientID":"31"},"payDatas":{"discountInfo":{"activeID":"0","discountID":"0","discountPrice":""},"payInfo":[{"bankType":"7","payCount":"3200","payTicketCount":"1","payType":"1"}],"payPass":"","returnUrl":"","totalPrice":"3200"},"processPath":"1","sessionKey":"mqneaadqapkpkqshxvdj","userID":"200394160"}
输出结果{"result":"ok","payExtInfo":{"alipayVerifyKey":"_input_charset=\"UTF-8\"&body=\"卖座网电子影票\"&it_b_pay=\"1h\"¬ify_url=\"http%3A%2F%2Fpay.maizuo.com%2FmobileBack.htm\"&out_trade_no=\"201507238712113008\"&partner=\"2088411628331920\"&payment_type=\"1\"&seller_id=\"2088411628331920\"&service=\"mobile.securitypay.pay\"&subject=\"深圳金逸影城沙井店(2D通兑票1张)\"&total_fee=\"32.00\"&sign=\"M0O0Ej5J13A25SAWupc5a6vAGmJnblx2CvuWF2dwFGxMZ%2BxlRWmp%2F6ZDfI8Y%2FFJbjiEqE99MAsKh%0AfIBQqP4Y1TyNkbY0XixQFPgAAqsqwGqYJSDtqUFWRgje%2B8pI1KuxfPE3UcDZs4hxDZoP%2Bdof%2Bldf%0AKQmximUyqT5Crtwj1Ag%3D\"&sign_type=\"RSA\""},"bankType":"","userId":"200394160","resource":{"rel":"view","link":"/orderform/200394160/201507238712113008"},"payType":"7","payUrl":"","orderId":"201507238712113008","uniqueKey":"D5585vO8624915A11z","timeNow":"1437622208552"}
3. 拿着支付串码,调用第三方服务,完成支付-->5分钟
4. 处理支付结果
1. 同步返回:支付后通知我们自己的apk
2. 异步通知:支付后通知我们的server
###什么是支付串码
> 这个是老师自己定义的一个概念.其实就是第三步调用起第三方支付平台`核心支付方法所需要的参数`
###集成支付宝流程
1. 我们自己要和支付宝签约(商户签约).-->运营
2. 秘钥配置-->协助运营完成秘钥的配置(公钥互换),可能程序员会参与
3. 集成支付宝-->必须是程序员去做.
1. 下载sdk/demo/文档
2. demo尝试的去运行
1. 出现了错误:因为缺少运行必须的,DEFAULT_PARTNER,DEFAULT_SELLER,如果1,2步完成的话,我们在这个时候就可以有`DEFAULT_PARTNER,DEFAULT_SELLER`
3. 开始集成-->`参照移动快捷支付应用集成接入包支付接口接入与使用规则.pdf`
1. 添加jar,alipay.jar
2. 添加lib,alipay_lib
3. 添加了一个activity
4. 添加了一些权限
5. 调用支付的核心代码
// 3.调用第三方服务,完成支付
//获取Alipay对象,构造参数为当前Activity和Handler实例对象
AliPay alipay = new AliPay(MainActivity.this, mHandler);
//调用pay方法,将订单信息传入
//同步返回 取消操作 支付成功 支付失败(网络异常)
String payResult = alipay.pay(alipayVerifyKey);
6. 处理支付结果--->支付宝处理支付结果用的handler机制
/**---------------demo里面处理支付结果的代码---------------**/
/*Result result = new Result((String) msg.obj);
switch (msg.what) {
case RQF_PAY:
case RQF_LOGIN: {
Toast.makeText(ExternalPartner.this, result.getResult(), Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
*/
/**---------------老师实际开发处理支付结果的代码---------------**/
/*Result.sResult = (String) msg.obj;
Logger.i(TAG, "strRet:" + Result.sResult);
try {
String errorMsg = Result.getPayResult();
Logger.i(TAG, "errorMsg:" + errorMsg);
if (!"".equals(errorMsg)) {
Toast.makeText(getApplicationContext(), errorMsg, 0).show();
if ("操作成功".equals(errorMsg)) {
payOk();//支付成功可以调到订单界面
} else {
payFail();//可以弹出对话框进行重复支付
}
}
} catch (Exception e) {
e.printStackTrace();
if (!PayActivity.this.isFinishing()) {
BaseHelper.showDialog(PayActivity.this, "提示", Result.sResult + ",如有疑问请联系卖座客服:4001808400", R.drawable.infoicon);
}
}
}
};*/
###支付宝demo分析
* 查看demo发现他的`支付串码`,是在客户端生成的.这个和老师所讲的.支付串码由服务器生成.有出入;
* 为了不暴露我们privatekey,我们应该把生成支付串码的过程交给我们的服务器
/**---------------生成支付串码的过程 begin---------------**/
Log.i("ExternalPartner", "onItemClick");
String info = getNewOrderInfo(position);
//其实下面的操作应该是server端去完成.不然我们会暴露privatekey---begin---add_by_billy
//所有我们会把info的具体内容用jsonString的形式.post给server进行签名.然后返回签名后的结果---add_by_billy
String sign = Rsa.sign(info, Keys.PRIVATE);
sign = URLEncoder.encode(sign);
info += "&sign=\"" + sign + "\"&" + getSignType();
Log.i("ExternalPartner", "start pay");
// start the pay.
Log.i(TAG, "info = " + info);
//其实下面的操作应该是server端去完成.不然我们会暴露privatekey---end---add_by_billy
final String orderInfo = info;
/**---------------生成支付串码的过程 end---------------**/
###支付串码_老师自己定义的一个概念
> 支付串码就是调用第三方应用的时候需要的一些核心的参数
###银联支付
* 银联支付,就`只需要一个交易流水号`就可以,而且看代码比较简单,重点是,`银联强制要求生产支付串码的过程必须交给我们的服务端`
* 集成形式
* 内嵌apk形式:就是把一个apk放到我们的assets目录下面-->老的方式
* 新版本so库形式:在libs下面就有很多的so库.已经不需要在assets目录下面放置apk
* 模式:
* 测试模式:银联会给我们提供一个测试环境+提供了一个银联的账号/密码
* 正式模式:就必须使用真实的账号/密码
* 运行demo看效果:
* 集成步骤:
* 1.添加libs里面相关的东西;
* 2.添加activity配置
<activity
android:name="com.unionpay.uppay.PayActivityEx"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="com.unionpay.uppay.PayActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:screenOrientation="portrait" />
* 3.添加权限
<!-- uupay -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
* 4.调用核心的支付方法
//拿着支付串码
System.out.println("alipayVerifyKey:" + alipayVerifyKey);
// 3.调用第三方服务,完成支付
// “00” – 银联正式环境
// “01” – 银联测试环境,该环境中不发生真实交易
//tn 交易流水号
UPPayAssistEx.startPayByJAR(MainActivity.this, PayActivity.class, null, null,
alipayVerifyKey, "00");
* 5.处理支付结果
/**---------------银联处理支付结果---------------**/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
/*************************************************
*
* 步骤4:处理银联手机支付控件返回的支付结果
*
************************************************/
if (data == null) {
return;
}
String msg = "";
/*
* 支付控件返回字符串:success、fail、cancel 分别代表支付成功,支付失败,支付取消
*/
String str = data.getExtras().getString("pay_result");
if (str.equalsIgnoreCase("success")) {
msg = "支付成功!";
} else if (str.equalsIgnoreCase("fail")) {
msg = "支付失败!";
} else if (str.equalsIgnoreCase("cancel")) {
msg = "用户取消了支付";
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("支付结果通知");
builder.setMessage(msg);
builder.setInverseBackgroundForced(true);
// builder.setCustomTitle();
builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
###微信支付
* 直接运行demo,发现最后提示错误,发现工程下面有一个debug.keystore
* 想要运行.可以如下操作
* 自定义keystore
* 或者直接导出的时候用工程下面的debug.keystore去签名
* 微信支付的安全策略之一:必须包名和keystore签名需要一致
* demo里面定义的步骤
* 一、获取 access_token
* 二、生成预支付订单,需要用到第一步的access_token,得到的是prepayId
* 三、调起微信支付
* 四、处理支付结果
* 这个时候一看.感觉微信支付很难.但是我们看到demo里面这样的一句话`注意:不能hardcode在客户端,建议genPackage这个过程由服务器端完成`,所以,其实我们的微信支付,一、二步骤为了安全起见应该交给Server
* 实际开发,只需关心3,4步就可以
* 三、调起微信支付
/**
* @author Administrator
* 支付的时候真正关心的数据
* 这个对象是我自己封装的.和微信支付的sdk没有关系
*/
public class WXPayData {
private String sign_method;
private String timestamp;
private String noncestr;
private String partnerid;
private String app_signature;
private String prepayid;
private String package1;
private String appid;
}
//核心支付方法
private void sendPayReq(WXPayData info) {
api = WXAPIFactory.createWXAPI(this, info.getAppid());
PayReq req = new PayReq();
req.appId = info.getAppid();
req.partnerId = info.getPartnerid();
req.prepayId = info.getPrepayid();//预支付id
req.nonceStr = info.getNoncestr();//32位内的随机串,防重发
req.timeStamp = String.valueOf(info.getTimestamp());//时间戳,为 1970 年 1 月 1 日 00:00 到请求发起时间的秒数
req.packageValue = info.getPackage1();
req.sign = info.getApp_signature();
// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
api.sendReq(req);
}
* 四、处理支付结果:微信支付支付的回调是在`net.sourceforge.simcpux.wxapi.WXPayEntryActivity.class`里面
@Override
public void onResp(BaseResp resp) {
Log.d(TAG, "onPayFinish, errCode = " + resp.errCode);
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.app_tip);
builder.setMessage(getString(R.string.pay_result_callback_msg, String.valueOf(resp.errCode)));
builder.show();
}
}
###安全码策略
> 安全码的组成规则为:Android签名证书的sha1值+“;”+packagename(即:数字签名+分号+包名)
* 作用:确定apk的唯一性
#项目案例与实战
* 课程来源
* 就业指导老师-->问题-->课程化
###出去如何提升自己
* 有很好的`开源意识`,`开放平台`思想
* `Libraries for developersV3.39`:众多开源效果集合-->国外-->只是提供了地址
* `android开源项目汇总`:众多开源效果集合-->国人-->只是提供了地址
* `baseAnimation`:众多开源效果-->针对动画效果-->国人-->开源的.需要效果的时候.要自行去找对应的代码
* `http://www.23code.com/`-->开源项目集合网站
* `http://a.code4app.com/`-->开源项目集合网站
* 一些demo的集合-->5000
* `http://apistore.baidu.com/astore/classificationservicelist/23.html`
* `https://github.com/Trinea/android-open-project `
* `http://apistore.baidu.com/`
* `http://www.androiddevtools.cn/`
* `深度理解`,`广度知道`
###Volley
* 回忆xutils:`快速开发型框架`,DbUtils(orm),ViewUtils(ioc),HttpUtils,BitmapUtils
* 其他的快速开发型框架:andBase,thinkandroid,loonandroid,dhroid
* orm:对象关系型映射
* db:create table t_table(_id integer primary key autoincret...);
* insert-->save(obj)
* ioc:控制反转
* Obj obj = new Obj();
* 对象的实例化,不用new关键字就可以了吧.
* 为什么要讲volley?
* 因为它是google出的,google 在2013 i/o大会上提出来的.
* 而且在几个项目里面已经看到了它的身影
* google公司为什么会去搞一个volley框架?
* 1.用户开启一个activity,然后加载网络,这个时候.如果用户点击了finish按钮.activity被销毁了-->网络请求和activity的生命周期是应该联动起来的.
* 2.listview加载图片的情况比较多.如果用户快速的去滑动listview-->getView->快速的加载图片,用户停止操作的时候.其实真正现实的图片最多就几张--->图片应该缓存起来(内存 +本地 )
* 3.如果用户打开了一个activity,用户旋转了一下屏幕.activity会旋转-->生命周期重走了-->网络请求缓存
* 4.之前我们的网络请求,httpurlconnection,httpclient,asynctask(api)-->android sdk-->封装性不够好.1000个开发者就有1000种使用方式-->不够统一
* 5.理念很容易理解,是开源的.
* volley是啥?
* 是一种`通信框架`,和xutils中的HttpUtils,BitmapUtils
###Volley两个核心类
* Request:一个请求
* StringRequest:请求的时候直接回来一个String
* JsonObjectRequest:请求的时候直接回来一个JsonObject
* JsonArrayRequest:请求的时候直接回来一个JsonArray
* ImageRequest:请求的时候直接回来一个Bitmap
* 自定义请求:一会我们会结合gson
* ImageLoader:图片的加载器
* NetWorkImageView:继承了imageView,对ImageView进行了拓展
* RequestQueue:请求队列.
###一步一步学习
###JsonObject取值
* String origin = response.getString("origin");// 方式一
* 这个如果没有对应的key会抛异常.需要异常处理
* String origin = response.optString("origin");// 方式二
* 这个如果没有对应的key不会抛异常.会返回一个默认值
* optString:默认值""
* optInt:默认值 0
* 比如有的实体bean属性很多.我们不喜欢去建议对应的XXX.class的时候.可以使用JsonObject里面的这个方法;
###图片
* 大图片的处理:
* 大图片处理的核心
* 核心类:BitmapFactory.Options
* 核心方法:
* decodeOptions.inJustDecodeBounds = true;-->得到图片的宽度以及高度,不需要把图片加载到内存 10M
* decodeOptions.inJustDecodeBounds = false;-->真正去加载图片
* decodeOptions.inSampleSize-->采样率-->不同的框架有不同的核心算法
* 特点:2 4 8 -->取值最好使用2的指数
* 图片的加载
* 图片的缓存
###框架找SampleSize的方式
1. volley
static int findBestSampleSize(
int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
double wr = (double) actualWidth / desiredWidth;
double hr = (double) actualHeight / desiredHeight;
double ratio = Math.min(wr, hr);
float n = 1.0f;
while ((n * 2) <= ratio) {
n *= 2;
}
return (int) n;
}
2. Xutils
public static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (width > maxWidth || height > maxHeight) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) maxHeight);
} else {
inSampleSize = Math.round((float) width / (float) maxWidth);
}
final float totalPixels = width * height;
final float maxTotalPixels = maxWidth * maxHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > maxTotalPixels) {
inSampleSize++;
}
}
return inSampleSize;
}
3. uil_imageLoader
public static int computeMinImageSampleSize(ImageSize srcSize) {
final int srcWidth = srcSize.getWidth();
final int srcHeight = srcSize.getHeight();
final int targetWidth = maxBitmapSize.getWidth();
final int targetHeight = maxBitmapSize.getHeight();
final int widthScale = (int) Math.ceil((float) srcWidth / targetWidth);
final int heightScale = (int) Math.ceil((float) srcHeight / targetHeight);
return Math.max(widthScale, heightScale); // max
}
public static int computeImageSampleSize(ImageSize srcSize, ImageSize targetSize, ViewScaleType viewScaleType,
boolean powerOf2Scale) {
final int srcWidth = srcSize.getWidth();
final int srcHeight = srcSize.getHeight();
final int targetWidth = targetSize.getWidth();
final int targetHeight = targetSize.getHeight();
int scale = 1;
switch (viewScaleType) {
case FIT_INSIDE:
if (powerOf2Scale) {
final int halfWidth = srcWidth / 2;
final int halfHeight = srcHeight / 2;
while ((halfWidth / scale) > targetWidth || (halfHeight / scale) > targetHeight) { // ||
scale *= 2;
}
} else {
scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max
}
break;
case CROP:
if (powerOf2Scale) {
final int halfWidth = srcWidth / 2;
final int halfHeight = srcHeight / 2;
while ((halfWidth / scale) > targetWidth && (halfHeight / scale) > targetHeight) { // &&
scale *= 2;
}
} else {
scale = Math.min(srcWidth / targetWidth, srcHeight / targetHeight); // min
}
break;
}
if (scale < 1) {
scale = 1;
}
scale = considerMaxTextureSize(srcWidth, srcHeight, scale, powerOf2Scale);
return scale;
}
###内存缓存
* 1.内存缓存的核心操作:
* 存:就有很多的考虑
* 取:只需要知道唯一的key就可以了
* 2.选择什么样的`存储结构/容器/集合`?set list map<String,Bitmap>
* 3.4种引用级别什么意思?
* 强引用:我们平时使用的集合(arraylist,hashmap,hashset),即使内存oom,也不会去回收对象;
* 软应用:使用SoftRefrence去包装一个对象,内存不足的时候去回收对象,尽量保证不oom
* 弱应用:基本没有用过
* 虚引用:形同虚设,同样没有用过
* 4.`删除策略/算法`,我们定义的`存储结构`,不能继续缓存图片的时候.需要进行清理
* LRU:最近最少使用,Least Recently Used,其实就是按照访问顺序排序
* 删除使用次数最少的:
* 删除占用体积最大:
* 5. 在很久之前(2,3年)前做图片的缓存基本都是使用软应用,但是在2.3之后.google文档明确指出了软应用做缓存的一些不足.建议我们使用LruCache.class;
* 6.举例说明`删除策略`的使用场景
* LRU:电影海报图删除策略-->和时间有关系(时效性)
* 删除使用次数最少的:-->和时间没有关系而且大小差不多
* 删除占用体积最大:空间比较宝贵的情况
###LruCache的使用:
> 一个工具方法,提供了基于`Lru缓存策略`的`强引用`的内存缓存,`存储结构使用的LinkedHashmap`
###LruCache实现原理
* LinkedHashmap使用
* LinkedHashmap和Hashmap区别:在构造方法里面多了3个参数
* 3个参数的意义:
* initialCapacity:初始化容器大小 16
* loadFactor:负载因子
* accessOrder:
* true:LinkedHash内部会排序-->按照访问顺序排序-->这个也是为什么LruCache使用LinkedHashmap做存储结构的原因
* false:按照插入顺序去排序
* LruCache在什么地方可以找到?
* 在高版本的sdk里面有.
* 在v4包中有提供.
* LruCache的使用
1. 告知缓存的具体大小
2. 覆写sizeOf方法,具体大小需要和我们定义的maxsize单位统一
###网络请求的取消
* httpclient:
DefaultHttpClient httpClient = new DefaultHttpClient();
ClientConnectionManager connectionManager = httpClient.getConnectionManager();// 拿到连接管理器
connectionManager.shutdown();
* httpurlconnection:
* volley:多级别取消
* 取消某一个请求:
* 取消请求的队列:
//2. 创建RequestQueue
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
//3. 发起请求
queue.add(stringRequest);
//取消单个请求
stringRequest.cancel();//取消一个请求
//取消所有请求
queue.cancelAll(null);//取消请求队列里面所有的方法
//取消置顶tag的请求
queue.cancelAll("tag1");//取消tag为tag1的一个请求
//请求添加tag-->tag的目的就是为了反查
stringRequest.setTag("tag1");
//两个不同的请求可以设置同一个tag
stringRequest.setTag("tag1");
// stringRequest1.setTag("tag1");
* xutils:xutils其实也是封装的httpclient,所以网络请求取消的方式和httpClient一样
* 生命周期的联动
StringRequest req1 = null;
StringRequest req2 = null;
StringRequest req3 = null;
StringRequest req4 = null;
StringRequest req5 = null;
req1.setTag(this.getClass().getSimpleName());
req2.setTag(this.getClass().getSimpleName());
req3.setTag(this.getClass().getSimpleName());
req4.setTag(this.getClass().getSimpleName());
req5.setTag(this.getClass().getSimpleName());
// 取消对应activity里面所有的请求
RequestQueue queue = VolleyTools.getInstance(MainActivity.this).getQueue();
queue.cancelAll(this.getClass().getSimpleName());// MainActivity
###uil imageLoader
* 3个核心类
* ImageLoaderConfiguration:imageloader的配置
* 简单的实例化方式
`ImageLoaderConfiguration config = ImageLoaderConfiguration.createDefault(getApplicationContext());`
* 自定义复杂的实例化方式
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.threadPriority(Thread.NORM_PRIORITY - 2)
.denyCacheImageMultipleSizesInMemory()
.diskCacheFileNameGenerator(new Md5FileNameGenerator())
.diskCacheSize(50 * 1024 * 1024) // 50 Mb
.tasksProcessingOrder(QueueProcessingType.LIFO)
.writeDebugLogs() // Remove for release app
.build();
* ImageLoader:图片加载器
* DisplayImageOptions:显示效果
* 支持圆角效果
* 支持淡入淡出效果
###uil imageloader和其他框架的区别
1. 丰富的缓存策略,配置比较丰富 差不多30个配置
2. 根据imageView的scalType进行计算缩放值 option.insamplesize
3. HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"),加载类型比较多
4. 提供了丰富的缓存策略
内存缓存
现在我们来看Universal-Image-Loader有哪些内存缓存策略
1. 只使用的是强引用缓存
LruMemoryCache(这个类就是这个开源框架默认的内存缓存类,缓存的是bitmap的强引用,下面我会从源码上面分析这个类)
2.使用强引用和弱引用相结合的缓存有
UsingFreqLimitedMemoryCache(如果缓存的图片总量超过限定值,先删除使用频率最小的bitmap)
LRULimitedMemoryCache(这个也是使用的lru算法,和LruMemoryCache不同的是,他缓存的是bitmap的弱引用)
FIFOLimitedMemoryCache(先进先出的缓存策略,当超过设定值,先删除最先加入缓存的bitmap)
LargestLimitedMemoryCache(当超过缓存限定值,先删除最大的bitmap对象)
LimitedAgeMemoryCache(当 bitmap加入缓存中的时间超过我们设定的值,将其删除)
3.只使用弱引用缓存
WeakMemoryCache(这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收
硬盘缓存
FileCountLimitedDiscCache(可以设定缓存图片的个数,当超过设定值,删除掉最先加入到硬盘的文件)
LimitedAgeDiscCache(设定文件存活的最长时间,当超过这个值,就删除该文件)
TotalSizeLimitedDiscCache(设定缓存bitmap的最大值,当超过这个值,删除最先加入到硬盘的文件)
UnlimitedDiscCache(这个缓存类没有任何的限制)
###架构
* b/s架构:绘图说明
* mvc:设计思想
* M:model javaBean domain
* V:view xml view adapter
* C:Ctroller Activity Fragment
* mvp:设计思想
* M:model
* V:View
* P:Presenter
* 四层架构:自我总结
* 数据提供层-->dataProvider:提供数据
* 数据持久层-->data persistent-->sqlite ,sp,file
* 业务逻辑层-->servcie logic
* ui展现层
###gzip
> 一种压缩格式,一种压缩方式,可以对`网络传输的数据`进行压缩.减少网络传输的大小
* 为什么需要压缩?
* 减少体积,提高传输速度,提高用户体验
* 浏览器发送器请求的过程?
* 1.发送请求头:`Accept-Encoding:gzip`
* 2.服务器压缩数据,返回数据,在响应头里面添加`Content-Encoding:gzip`
* 3.客户端,根据Content-Encoding这个响应头,对应解压
* 有Content-Encoding:gzip-->gzip解压
* 没有Content-Encoding:gzip-->标准解压
* app使用gzip压缩
* 返回的json/xml(文本信息)其实就是个特殊的网页,其实也是可以进行gzip压缩
###gzip压缩效果
> 通过数据,我们得知,文本的压缩率,大概可以达到70%左右.压缩率很高;
###gzip压缩的实现
try {
boolean isGzip = false;
//1.创建httpclient
DefaultHttpClient httpClient = new DefaultHttpClient();
//2.创建get请求
HttpGet get = new HttpGet("http://httpbin.org/gzip");
//① 添加请求头 Accept-Encoding:"gzip, deflate"
get.addHeader("Accept-Encoding", "gzip");
//3.执行请求
HttpResponse response = httpClient.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
//② 得到响应头,Content-Encoding:"gzip"
Header[] headers = response.getHeaders("Content-Encoding");
for (Header header : headers) {
if (header.getValue().equals("gzip")) {//后台server把数据进行了gzip压缩
isGzip = true;
}
}
String result = "";
HttpEntity entity = response.getEntity();
//③根据是否使用gzip压缩.采取不同的解压方式
if (isGzip) {
//④进行gzip的解压
GZIPInputStream in = new GZIPInputStream(response.getEntity().getContent());
//in-->string
result = convertStreamToString(in);
} else {
//4.打印结果
result = EntityUtils.toString(entity);
}
System.out.println("result:" + result);
}
} catch (Exception e) {
e.printStackTrace();
}
###测试请求的地址
> `http://httpbin.org`
###常见的content-type
* application/x-www-form-urlencoded:表单,key-value
* multipart/form-data:二进制,file
* **application/json** :json,虽然有的服务器直接用`text/plain`这个请求头没有任何问题.但是很多服务器,必须需要`application/json`,明确的说.如果是返回json,一定加上`application/json`,不要用默认的.实际开发遇到了几次这样的问题.或者说.**加上这个请求头肯定是万无一失**;
* text/xml :xml
* text/plain:普通文本,默认类型
###模拟请求插件restClient的使用
> 这个是firefox上的一个插件,对应chrome浏览器叫做postman,这个插件主要用作和服务器开发人员联调协议;
* key-value:
* 1.添加head-->Content-Type
* 2.传递参数:key=value&key=value
* jsonString
* 1.添加head
* 2.传递参数:jsonString
Android 面试点相关推荐
- android progressbar 不显示_Android多线程技术选型最全指南(1)
码个蛋(codeegg) 第 935 次推文 作者:qing的世界 链接:https://juejin.im/post/5d1eb4acf265da1bb003de71 前言 前段时间在组内做了一下现 ...
- 你所不知道的 Android Studio 调试技巧
Android Studio目前已经成为开发Android的主要工具,用熟了可谓相当顺手.作为开发者,调试并发现bug,进而解决,可是我们的看家本领.正所谓,工欲善其事必先利其器,和其他开发工具一样, ...
- 你所不知道的Android Studio调试技巧
原文链接:简书@涅槃1992 http://www.jianshu.com/p/011eb88f4e0d Android Studio目前已经成为开发Android的主要工具,用熟了可谓相当顺手.作为 ...
- 最新BAT大厂面试者整理的Android面试题目模板,分享PDF高清版
前言 从毕业到现在面试也就那么几家公司,单前几次都比较顺利,在面到第三家时都给到了我offer!前面两次找工作,没考虑到以后需要什么,自己的对未来的规划是什么,只要有份工作,工资符合自己的要求就行!所 ...
- android dp sp px_Android屏幕适配★★重点盘点★★
引言 屏幕适配是 android 开发/面试 绕不开的一个问题.本文 将屏幕适配的知识要点完整展现给各位读者. 正文大纲 android需要做屏幕适配的原因 基础知识点(★★★很重要★★★) 屏幕适配 ...
- 马云再谈对钱没有兴趣;比尔·盖茨:微软原本可以击败 Android!TypeScript 3.7 发布 | 极客头条...
作者 | 唐小引 出品 | CSDN(ID:CSDNnews) 快来收听极客头条音频版吧,智能播报由标贝科技提供技术支持. 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客 ...
- Android 初级探讨 OOM问题 以及解决优化之道
前言:本文章只是简单阐述实际开发中遇到的OOM 问题 本文不会涉及太多很深的技术点,我也不懂,哈哈啊哈哈哈哈~ (一) 什么是OOM? 1: 这是一个面试官经常会问到的问题 OOM就是内存溢出,即Ou ...
- WIFi 开关控制实现-ESP8266 物联网 android studio arduino QT多线程服务器
WIFi 开关控制实现-ESP8266 物联网 android studio arduino QT多线程服务器 WIFI局域网/外网 开关控制实现-物联网ESP8266 android QT 简介:本 ...
- android蓝牙门禁,1号社区APP互联门禁产品新开门方式说明
原标题:1号社区APP互联门禁产品新开门方式说明 一.新开门方式版本详细说明 1.开门要素 苹果手机: 1)"设置"页面"手机开门"打开 2)手机打开蓝牙 3) ...
最新文章
- sources root pycharm 怎么设置_使用python语言开发ROOT之搭建环境方法探索
- wpf异形按钮,定制异型按钮在WPF
- 初二计算机辅导记录,(初中信息技术兴趣小组活动记录.doc
- NET问答: 为什么 String.IndexOf 在 .net5 和 netcore3 中返回值不一样?
- java仿聊天室项目总结_Java团队课程设计-socket聊天室(Day4总结篇)
- 用线程实现动态改变图标
- Linux内核编译:很少有人提及的一些内容
- 忍不住跟着吐槽 —“当你辛辛苦苦写的博客文章被无情复制,成为了他的原创,你作何感想?”...
- 华为p10应用市场无法连接服务器,华为p10如何连接电脑及没反应怎么解决【图文教程】...
- 2019最新java实战项目资料
- 主流流媒体服务器软件,十款免费的流媒体服务器软件介绍
- HTML基础学习(菜鸟教程和W3school参考手册)
- LaTex中各种文本框
- 施一公:如何写好一篇学术论文?
- Linux误删数据恢复实验
- MAC 安装windows
- 结算时打印购物小票,计算此次获得的会员积分
- 干货分享|串流游戏软件大比拼
- redis面试题(一)赋答案
- USES_CONVERSION的使用和注意
热门文章
- EMC 共模电感选型
- git与gitee的基础使用方法
- Activiti-5.22.0——activiti-modeler界面设计组件介绍
- 《崔庆才Python3网络爬虫开发实战教程》学习笔记(5):将爬虫爬取到的数据存储到TXT,Word,Excel,Json等文件中
- ? 精美图文带你掌握 JVM 内存布局
- Lync Server 2013视频会议架构
- 字符串java_字符串的常用方法(内建函数)
- C51接入OneNET-实现数据上传和命令下发
- 计算机更新系统d盘东西还在吗,电脑换系统后东西还在不在
- 广告拦截—Adblocks Plus (F*cking shit Ads!