Android 性能优化-网络优化

http 1.0 TCP链接不复用
http 1.1 引入持久连接,数据按照次序进行
http 2.0 多工 客户端服务端 双向实时通信

1.网络检测工具

1. Network Profiler

只支持httpurlconnection 和okhttp 请求
开启高级分析 run --edit configure —profiling

androidstudio 高版本都已经支持该功能

2.charles

Charles 是在 PC 端常用的网络封包截取工具,在做移动开发时,我们为了调试与服务器端的网络通讯协议,常常需要截取网络封包来分析。除了在做移动开发中调试端口外,Charles 也可以用于分析第三方应用的通讯协议。配合 Charles 的 SSL 功能,Charles 还可以分析 Https 协议。
可以模拟弱网 使用本地数据模拟接口、断点连接。
https://juejin.cn/post/6844903665304600589

3.stetho

可以查看设备的数据库 、网络请求、
https://github.com/facebook/stetho

implementation 'com.facebook.stetho:stetho:1.6.0'

public class MyApplication extends Application {
    
    
  public void onCreate() {
    
    
    super.onCreate();
    Stetho.initializeWithDefaults(this);
  }
}

在chrome里 输入 chrome://inspect/#devices :

连接设备就可以查看了

2.精准获取流量

设置–流量管理
抓包工具:只允许APP联网

1 NetworkStatsManager (推荐)

NetworkStatsManager Api 23 以后监测流量的方案.
可以指定时间间隔内的流量信息,可以线上使用。
不同网络类型下的消耗。

    @RequiresApi(api = Build.VERSION_CODES.M)
    public static long getNetStats(@NonNull Context context, long startTime, long endTime, int netType) {
    
    
        long netDataReceive = 0;
        long netDataSend = 0;
        String subId = null;
//        获取服务对象
        NetworkStatsManager manager = (NetworkStatsManager) context.getApplicationContext().
                getSystemService(Context.NETWORK_STATS_SERVICE);

        if (manager == null) {
    
    
            return 0;
        }
        NetworkStats networkStats = null;
//        流量桶
        NetworkStats.Bucket bucket = new NetworkStats.Bucket();
        try {
    
    
            networkStats = manager.querySummary(netType, subId, startTime, endTime);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

        while (networkStats != null && networkStats.hasNextBucket()) {
    
    
            networkStats.getNextBucket(bucket);
            int uid = bucket.getUid();
            //只获取本APP的流量
            if (getAppUid(context) == uid) {
    
    
                netDataReceive += bucket.getRxBytes();
                netDataSend += bucket.getTxBytes();
            }
        }
        return (netDataReceive + netDataSend);
    }

TrafficStats
Api18以上使用,重启以来的流量数据,以前的数据会被删除,了解即可
不能获取某个时间段内的流量消耗。

2.后台流量检测方案

后台定时任务—获取间隔内流量–记录前后台–分别计算–上报APM后台–流量处理

3.数据缓存

给okhttp 添加cache拦截器。在无网络的情况下,缓存上次的数据。

4.数据压缩

post请求body使用Gzip压缩
请求头压缩

5.图片压缩上传

luban 第三方库
https://github.com/Curzibn/Luban

implementation 'top.zibin:Luban:1.1.8'

load 传入原图
filter 设置开启压缩条件
ignoreBy 不压缩的阈值,单位为K
setFocusAlpha 设置是否保留透明通道
setTargetDir 缓存压缩图片路径
setCompressListener 压缩回调接口
setRenameListener 压缩前重命名接口

Luban.with(holder.imageView.getContext())
        .load(Environment.getExternalStorageDirectory()+"/Android/1.jpg")
        .setTargetDir(Environment.getExternalStorageDirectory()+"/Android")
        .launch();

6.网络质量差 (DNS)

请求成功率
请求速度快

请求到达运营商DNS相关 (DNS被劫持,DNS解析慢)
HttpDNS 绕过运营商域名解析过程。
降低访问平均时长。

使用阿里云提供DNS服务

compile ('com.aliyun.ams:alicloud-android-httpdns:1.1.7@aar') {
    
    
        transitive true
 }
public class OkHttpDNS implements Dns {
    
    

    private HttpDnsService dnsService;
    private static OkHttpDNS instance = null;

    private OkHttpDNS(Context context) {
    
    
        dnsService = HttpDns.getService(context, "");
    }

    public static OkHttpDNS getIns(Context context) {
    
    
        if (instance == null) {
    
    
            synchronized (OkHttpDNS.class) {
    
    
                if (instance == null) {
    
    
                    instance = new OkHttpDNS(context);
                }
            }
        }
        return instance;
    }

    @Override
    public List<InetAddress> lookup(String hostname) throws UnknownHostException {
    
    
        String ip = dnsService.getIpByHostAsync(hostname);
        if(ip != null){
    
    
            List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));
            return inetAddresses;
        }
        return Dns.SYSTEM.lookup(hostname);
    }
}

//伪代码
okhttpClientBuilder.dns(OkHttpDNS.getIns(PerformanceApp.getApplication())).build();

7.监控每次发生请求的时间

继承okhttp里的EventListener,来监听每个请求的多个动作。

 
public class OkHttpEventListener extends EventListener {
    
    

    public static final Factory FACTORY = new Factory() {
    
    
        @Override
        public EventListener create(Call call) {
    
    
            return new OkHttpEventListener();
        }
    };

    OkHttpEvent okHttpEvent;
    public OkHttpEventListener() {
    
    
        super();
        okHttpEvent = new OkHttpEvent();
    }

    @Override
    public void callStart(Call call) {
    
    
        super.callStart(call);
        Log.i("lz","callStart");
    }
	
    @Override
    public void dnsStart(Call call, String domainName) {
    
    
        super.dnsStart(call, domainName);
        okHttpEvent.dnsStartTime = System.currentTimeMillis();
    }

    @Override
    public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
    
    
        super.dnsEnd(call, domainName, inetAddressList);
        okHttpEvent.dnsEndTime = System.currentTimeMillis();
    }

    @Override
    public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {
    
    
        super.connectStart(call, inetSocketAddress, proxy);
    }

    @Override
    public void secureConnectStart(Call call) {
    
    
        super.secureConnectStart(call);
    }

    @Override
    public void secureConnectEnd(Call call, @Nullable Handshake handshake) {
    
    
        super.secureConnectEnd(call, handshake);
    }

    @Override
    public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, @Nullable Protocol protocol) {
    
    
        super.connectEnd(call, inetSocketAddress, proxy, protocol);
    }

    @Override
    public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, @Nullable Protocol protocol, IOException ioe) {
    
    
        super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe);
    }

    @Override
    public void connectionAcquired(Call call, Connection connection) {
    
    
        super.connectionAcquired(call, connection);
    }

    @Override
    public void connectionReleased(Call call, Connection connection) {
    
    
        super.connectionReleased(call, connection);
    }

    @Override
    public void requestHeadersStart(Call call) {
    
    
        super.requestHeadersStart(call);
    }

    @Override
    public void requestHeadersEnd(Call call, Request request) {
    
    
        super.requestHeadersEnd(call, request);
    }

    @Override
    public void requestBodyStart(Call call) {
    
    
        super.requestBodyStart(call);
    }

    @Override
    public void requestBodyEnd(Call call, long byteCount) {
    
    
        super.requestBodyEnd(call, byteCount);
    }

    @Override
    public void responseHeadersStart(Call call) {
    
    
        super.responseHeadersStart(call);
    }

    @Override
    public void responseHeadersEnd(Call call, Response response) {
    
    
        super.responseHeadersEnd(call, response);
    }

    @Override
    public void responseBodyStart(Call call) {
    
    
        super.responseBodyStart(call);
    }

    @Override
    public void responseBodyEnd(Call call, long byteCount) {
    
    
        super.responseBodyEnd(call, byteCount);
        okHttpEvent.responseBodySize = byteCount;
    }

    @Override
    public void callEnd(Call call) {
    
    
        super.callEnd(call);
        okHttpEvent.apiSuccess = true;
    }

    @Override
    public void callFailed(Call call, IOException ioe) {
    
    
        Log.i("lz","callFailed ");
        super.callFailed(call, ioe);
        okHttpEvent.apiSuccess = false;
        okHttpEvent.errorReason = Log.getStackTraceString(ioe);
        Log.i("lz","reason "+okHttpEvent.errorReason);
    }
}

使用

okhttpclientbuilder.eventListenerFactory(OkHttpEventListener.FACTORY).

Guess you like

Origin blog.csdn.net/chentaishan/article/details/118599245