#SQL语法

一、Dom4j解析(需要导入Dom4j.jar):

import java.io.FileOutputStream;
import java.io.IOException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

public class Dom4jUtil {
    private static final String DEFAULT_PATH = "src/com/cuncaojin/xmlFile.xml";

    private Dom4jUtil() {
    }

    public static Document getDocument(String filePath) throws DocumentException {
        SAXReader saxReader = new SAXReader();
        filePath = filePath == null ? DEFAULT_PATH : filePath;
        return saxReader.read(filePath);
    }

    public  void write2XML(Document document, String filePath) throws IOException {
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        filePath = filePath == null ? DEFAULT_PATH : filePath;
        XMLWriter writer = new XMLWriter(new FileOutputStream(filePath), format);
        writer.write(document);
        writer.close();
    }
}

二、XPath解析(依赖Dom4j解析技术,需要导入Dom4j.jar和jaxen-1.1-beta-6.jar包):

import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class Demo {
    public static void main(java.lang.String[] args) throws Exception {
        String path = "myxml.xml";
        Document document = new SAXReader().read(path);
        List<Element> selectNodes = document.selectNodes("//addr[@id='addrs']");
        // List<Element> selectNodes = document.selectNodes("//addr");
        for (Node node : selectNodes) {
            System.out.println(node.getText());
        }
    }
}

1、结合Dom4j获取Document对象(XPath解析技术依赖Dom4j解析技术)
2、导入Dom4j.jar和jaxen-1.1-beta-6.jar
3、如果想使用XPATH语言,条件:只能使用node节点对象中的两个方法:
    List selectNodes(String xpathExpression);
    Node selectSingleNode(String xpathExpression);
4、xpathExpression的写法,查文档

#SQL语法

###数据库

  • 连接: mysql -uroot -proot
  • 创建: create database databaseName [character set utf8/gbk] ;
  • 使用: use databaseName
  • 查看: show databases;
  • 查看数据库定义信息: show create database databaseName;
  • 删除: drop database databaseName
  • 修改: alter database databaseName character set utf8 [collate 校对规则];
  • 查看当前使用的数据库: select database();

###表

  • 创建: create table tableName(id int primary key auto_increment,username varchar(40) not null unique,password varchar(40) not null,date date);
  • 查看表: show tables;
  • 查看某个表结构: desc tables;
  • 删除表: drop table tableName;
  • 修改表:
    • 添加列: alter table tableName add colName varchar(40) unique not null;
    • 删除列: alter table tableName drop colName;
    • 修改列类型、长度和约束: alter table tableName modify colName int(150);
    • 修改列名称: alter table tableName change oldColName newColName varchar(40) not null unique;
    • 修改表名: rename table oldTableName to newTableName;
    • 修改表的字符集: alter table tableName character set gbk/utf8;

###记录

  • 插入:
    • 格式1: - insert into tableName (colName1,colName2,…) values (value1,value2,…);
      • 格式2: insert into tableName values (value1,value2,…);
    • 中文乱码,修改:找到MySQL的安装路径下的my.ini文件,修改文件中[client]下的字符集default-character-set=gbk,重启mysql,services.msc
  • 修改: update tableName set colName=value,colName2=value2,… [where 条件];
  • 删除: delete from tableName [where 条件]
  • 查询: S(select)… F(from)…W(where)…G(group by)…H(having)…O(order by);
    • select [/colName1,colName2,… [as nickname]]* from tableName [where 条件];
      • 条件查询:
    • , < , >= , <= , <> ,=

    • like:模糊查询
      • like可以进行模糊查询,在like子句中可以使用或者%作为占位符。只能代表一个字符,而%可以代表任意个字符。
      • like ‘李_’ :名字中必须是两个字,而且是姓李的。
      • like ‘李%’ :名字中姓李的学生,李子后可以是1个或任意个字符。
      • like ‘%四’ :名字中以四结尾的。
      • like ‘%王%’ :只要名称中包含这个字就可以。
    • in:范围查询
      • select * from exam where english in (69,75,89);
    • 条件关联:and , or ,not
      • 排序查询: order by 字段名称 asc/desc;
    • select * from exam where name like ‘李%’ order by chinese desc,english asc;
      • 聚合函数:
    • sum() select sum(english + chinese + math) from exam;
    • count() select count(*) from exam;
    • max() select max(math) from exam;
    • min() select min(chinese) from exam;
    • avg() select avg(chinese) from exam;
      • 分组查询: select product,count(*) from orderitem group by product;
        • where的子句后面不能跟着聚合函数。如果现在使用带有聚合函数的条件过滤(分组后条件过滤)需要使用一个关键字having
          • select product,sum(price) from orderitem group by product having sum(price) > 5000 order by sum(price) asc;

Android Scroll分析 ——《群英传》第五章

滑动的7种方法

1.layout(int left,int top ,int right, int right)
    * left/top/right/right均为绝对坐标
2.offsetLeftAndRight和offsetTopAndBottom
    * 与layout用法相同,是对layout方法的封装 
3.LayoutParams
    * **LinearLayout.LayoutParams** params = (LinearLayout.LayoutParams)getLayoutParams();
    * params.leftMargin = getLeft() + offsetX();
    * params.topMargin = getRight()+ offsetY();
    * setLayoutParams(params);

    * **ViewGroup.MarginLayoutParams** params = (ViewGroup.MarginLayoutParams)getLayoutParams();
    * 同上
4.ScrollTo和ScrollBy
    ((View)getParent()).scrollBy(offsetX, offsetY);
    注意:
    1)移动的是内容。如果是ViewGroup,则移动的是子View;如果移动的是TextView,则移动的是文字;如果移动的是ImageView,则移动的是drawable
    2)坐标参考系
        这个比较特殊,可以理解为移动的是屏幕,而非View。举例:一个绝对坐标为(20,10)的Button,如果对其使用((View)getParent()).scrollBy(20,10),则这个按钮将被移动到(0,0)。
5.Scroller
6.属性动画 
7.ViewDragHelper

Android 绘图 ——Android群英传 学习笔记

FontMatrics部分参考:http://mikewang.blog.51cto.com/3826268/871765

核心类

1.Canvas 画布
2.Bitmap 纸
3.Paint 笔
4.{
    FontMetrics
    PorterDuffXfermode
    Matrix(3x3矩阵) 
    ColorMatrix(4x5矩阵)
    ColorFilter
    Shader
    PathEffect
}
5. SurfaceView P155,有固定模版用法

思想

1.一般初始化Canvas时,要传入一个Bitmap,之后的所有的绘制效果都将呈现在Bitmap上。
    Bitmap mPaper = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mPaper);
    mCanvas.drawBitmap(bm, 0, 0, paint);//将bm用画笔paint画到mPager上
2.在onDraw(canvas)方法中,只需要将步骤1中的纸mPaper绘制到系统提供的画布canvas上即可。
    canvas.drawBitmap(mPaper, 0, 0, null);
3.Paint 
    具有非常强大的功能:
    1)PorterDuffXfermode 滤镜功能:
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        设置混合模式,具体效果参考文档,或Android群英传P146.
    2)获取FontMetrics,测量文本尺寸
        Paint.FontMetrics fm = mPaint.getFontMetrics();
        FontMetrics属性:{
            1. 基准点是baseline
            2. ascent是baseline之上至字符最高处的距离
            3. descent是baseline之下至字符最低处的距离
            4. leading文档说的很含糊,其实是上一行字符的descent到下一行的ascent之间的距离
            5. top指的是指的是最高字符到baseline的值,即ascent的最大值
            6. 同上,bottom指的是最下字符到baseline的值,即descent的最大值

            说明:ascent/descent/top/bottom,这几个值均表示距离baseline的距离。举例:ascent的值,即为字符最高处的y坐标减去baseline的y坐标之差。所以,其永远为负值。同理,descent/bottom永远为正值。
        }

        float baseY = - fm.top;
        mCanvas.drawText("cuncaojin", 0, baseY, mPaint);

        ![](http://img1.51cto.com/attachment/201205/204735397.png)
    3)Style(空心/实心)
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    4)setColorFilter
        ColorMatrix imageMatrix = new ColorMatrix();
        //颜色矩阵,可以设置色调、饱和度、亮度
        imageMatrix.setRotate(0/1/2,hue);//0,1,2——R,G,B 色调
        imageMatrix.setSaturation(saturation);//饱和度为0时,图像为灰度图像
        imageMatrix.setScale(lum, lum, lum, 1);//亮度
        imageMatrix.postConcat(anotherColorMatrix);//将颜色矩阵叠加
        paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));

    5)setShader():主要作用是作为遮罩层,产生特殊效果
        Shader(渲染器)类实现类有{
            a. BitmapShader 位图Shader (相比其他Shader比较特殊)
                {
                    用BitmapShader填充时的3种模式:
                        CLAMP 拉伸
                        REPEAT 重复
                        MIRROR 镜像
                }
            b. LinearGradient 线性Shader
            c. RadialGradient 光束Shader
            d. SweepGradient 梯度Shader
            e. ComposeShader 混合Shader
        }


    6)setPathEffect 路径效果
        a. null    
        b. CornerPathEffect    路径圆滑处理
        c. DiscretePathEffect    产生杂点
        d. DashPathEffect    虚线化
        e. PathDashPathEffect    可设置虚线图形
        f. ComposePathEffect    可组合以上效果


    7)其他属性{
        setAntiAlias(true); 抗锯齿
        setStrokeJoin(Paint.Join.ROUND); 设置笔连接处圆滑处理
        setStrokeCap(Paint.Cap.ROUND); 设置笔触圆滑处理
        setStrokeWidth(50);    设置笔宽
        setColor();    
        setARGB();
        setAlpah();
        setTextSize();
    }    
4.Canvas
    1)绘制{
        drawPoint
        drawLine
        drawRect
        drawRoundRect
        drawArc 绘制扇形或弧形(由参数useCenter决定,true扇形,false弧形,设置Paint.Style决定是空心还是实心)
        drawOval 绘制椭圆
        drawText 
        drawPosText(text, new float[]{x1,y1,x2,y2,...xn,yn}, paint) 在指定位置逐个对每个字符绘制    
        drawPath 绘制路径
        drawBitmap
    }
    2)结合Matrix
        Matrix matrix = new Matrix();
        matrix{
            setRotate()
            setTranslate();    
            setScale();    
            setSkew(); 错切变换/剪切变换
            pre() 先乘
            post() 后乘
        }
        canvas.drawBitmap(mBitmap, matrix ,null);
        ---------------------------------------------
        Canvas mCanvas = new Canvas(mBmp);
        Matrix matrix = new Matrix();
        float scale = w * 1f / getResources().getDisplayMetrics().widthPixels;
        matrix.setScale(scale, scale);
        mCanvas.drawBitmap(bitmap, matrix, mPaint);
    3)Canvas的其他方法{
        save() 将之前绘制的所有图像进行保存
        restore() 将save()之后绘制的所有图像与save()之前的图像进行合并
        translate() 
        rotate()
    }

Demo:

自定义一个圆形图,实现方案{
    1)使用paint.setXferMode(new PorterXferMode(...))
        a. 绘制圆
        b. 对画笔设置PorterDuffXfermode(SRC_IN)则上步绘制的圆作为遮罩层
        c. (设置缩放比例等)优化绘图效果
        d. 绘制图片
    2) 使用paint.setShader(new BitmapShader(...))
        a. 对画笔设置渲染器为BitmapShader,模式选择拉伸
            mPaint.setShader(new BitmapShader(mBmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
        b. (设置缩放比例等)优化绘图效果
        c. 绘制圆
}

参考代码如下:

方案一:
public CircleView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();

    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
    int indexCount = typedArray.getIndexCount();
    for (int i = 0; i < indexCount; i++) {
        int index = typedArray.getIndex(i);
        switch (index) {
            case R.styleable.CircleView_src:

                BitmapDrawable drawable = (BitmapDrawable) typedArray.getDrawable(index);
                mBitmap = drawable.getBitmap();
                break;
        }
    }
    typedArray.recycle();
}

private void init() {
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    mPaper = Bitmap.createBitmap(w, w, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mPaper);
    mPaint.setTextSize(50);
    mPaint.setStrokeWidth(5);
    mPaint.setARGB(255, 255, 0, 0);
    mPaint.setColor(0xff00ff00);
    mPaint.setTextAlign(Paint.Align.LEFT);

    Paint.FontMetrics fm = mPaint.getFontMetrics();
    Log.i("tag", fm.ascent + ", leading:" + fm.leading + " ,descent:" + fm.descent + ", bottom:" + fm.bottom + ", " + fm.top);
    float baseY = -fm.ascent;
    mCanvas.drawText("寸草金CUNJQjinsdaofihwafehofdmvpBGEOUWmevldnbuehwPOS:lXM", 0, baseY, mPaint);

    Path path = new Path();
    path.moveTo(0, 50);
    path.lineTo(100, 200);
    mCanvas.drawPath(path, mPaint);

    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));

    RectF rect = new RectF(0, 0, w, h);
    mCanvas.drawRoundRect(rect, 50, 50, mPaint);

    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

    Matrix matrix = new Matrix();
    matrix.setScale(w * 1f / mBitmap.getWidth(), w * 1f / mBitmap.getWidth());
    mCanvas.drawBitmap(mBitmap, matrix, mPaint);
}

方案二:
private void init(Context context, AttributeSet attrs) {
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic1);
    mBmp = Bitmap.createBitmap(w, w, Bitmap.Config.ARGB_8888);

    Canvas mCanvas = new Canvas(mBmp);
    Matrix matrix = new Matrix();
    float scale = w * 1f / getResources().getDisplayMetrics().widthPixels;
    matrix.setScale(scale, scale);
    mCanvas.drawBitmap(bitmap, matrix, mPaint);

    mPaint.setShader(new BitmapShader(mBmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(widthMeasureSpec, widthMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int r = getWidth() / 2;
    canvas.drawCircle(r, r, r, mPaint);
}

蚂蚁金服. 开放平台. 文档中心

参考1:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.jKJinz&treeId=291&articleId=106103&docType=1

参考2:http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html?spm=a219a.7629140.0.0.jtOMMW (数字签名)

1.RSA和RSA2区别:
    详细参见:
    https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.y7rDdS&treeId=291&articleId=106115&docType=1
    简单来说,签名主要包含两个过程:摘要和非对称加密,
    首先对需要签名的数据做摘要(类似于常见的MD5)后得到摘要结果,然后通过签名者的私钥对摘要结果进行非对称加密即可得到签名结果。

    开放平台支持的签名算法
    开放平台签名算法名称        标准签名算法名称                        备注
    RSA2                    SHA256WithRSA        (强烈推荐使用),强制要求RSA密钥的长度至少为2048,
    RSA                        SHA1WithRSA            对RSA密钥的长度不限制,推荐使用2048位以上

MVP学习笔记

Sorry,引用文章的地址给忘了哪几个了。忘原作者见谅。

M:Model,关注数据处理
V:View,关注处理视图的可视化及与用户交互
P:Presenter,关注业务处理

###在MVP模式里通常包含4个要素:
(1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);
(2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;
(3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);
(4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

###总结:

V:持有P的引用,项目规格不大,可以不使用P的接口
P:持有M、V的接口实现对象

**Note:** 
防止Activity或Fragment声明周期结束后,一般执行耗时操作的Presenter层因为持有对Activity或Fragment的强引用,导致内存泄漏。

**处理方法:**
1.  解除绑定关系,在V层生命周期的OnDestory()中,调用P层持有的V,将其置空,解除和P层的关联。
2.  为了弥补在特殊情况下,如系统突然回收内存,导致Activity的onStop、onDestory没有执行便被干掉,造成上一种方式解除绑定代码没有被执行,特还需要使用软引用或弱引用。


/**
 * code from Android源码设计模式
 */
public abstract class BasePresenter<T> {
    protected Reference<T> mViewRef;

    public void attachView(T view) {
        mViewRef = new WeakReference<T>(view);
    }

    protected T getView() {
        return mViewRef.get();
    }

    protected void detachView() {
        if (mViewRef != null) {
            mViewRef.clear();
            mViewRef = null;
        }
    }
}

public abstract class MVPBaseActivity<V, T extends BasePresenter<V>> extends AppCompatActivity {
    BasePresenter mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPresenter = createPresenter();
        mPresenter.attachView((V) this);
    }

    public abstract T createPresenter();

    @Override
    public void onDestroy() {
        mPresenter.detachView();
    }
}

URL由http到https重定向,URLConnection下载失败

参考1:分析为何使用URLConnection下载文件失败的原因

参考2:具体解决HttpURLConnection重定向问题参考代码

拷贝自参考1文章部分:(防止源网页不可用,感謝原作者填坑)
URLConnection从HTTP重定向到HTTPS
也不知什么原因,公司项目的服务端一直在吸引着大波攻击,于是服务端的同学打算把所有HTTP的请求都换为HTTPS,他们决定兼容旧版本于是就将之前的所有HTTP请求全部重定向到另一个HTTPS请求。 
项目请求框架搭建初期,考虑到应用也不会使用太复杂的请求模式,于是就简单使用URLConnection完成服务端交互。服务端一修改,全部请求都失败了。虽然URLConnection有是否遵循重定向开关(setInstanceFollowRedirects),其默认就是开启的,即便你再强制其打开,也是没有用,问题依旧。找了大量资料,其实问题的关键点不是重定向而是从HTTP重定向到HTTPS,关键点就在URLConnection的两个子类上。

HttpURLConnection与HttpsURLConnection
HttpURLConnection为URLConnection的子类,而HttpsURLConnection为HttpURLConnection的子类,在HttpURLConnection基础上对HTTPS进行支持。 
URLConnection通常使用URL的openConnection()方法获得,而URL是根据其是否为Https开头来打开一个HttpURLConnection还是HttpsURLConnection。 
而当URLConnection进行connect()时,遇到了重定向,如果打开了遵循重定向,那么其会获取重定向的地址,然后尝试连接这个地址。值得注意的是,这时候并不是使用新的链接地址重新openConnection()一个URLConnection,而是直接尝试连接这个重定向的地址,否则也就不存在以上的Bug了。 
于是理论上分析,HTTP重定向到HTTP是不存在问题的,HTTPS重定向到HTTPS也是不存在问题的,而HTTP与HTTPS之间的重定向,那么就很可能会有问题了。HTTP重定向到HTTPS,URLConnection会将重定向的HTTPS以HTTP方式继续提交,那么服务端肯定是认为你是错误的提交方式;同理,HTTPS重定向HTTP也一样。

问题解决
使用URLConnection抓取到重定向,就使用重定向的地址重新人为openConnection()一个新的URLConnection重新请求。
使用第三方请求框架,如OKHttp。
具体项目具体分析,方法一是可行的,但是处理起来就很麻烦了。而方案二则更可选,因为URLConnection与OKHttp用法其实差不了多远

##URLConnection支持302重定向,Demo

`
package com.cuncaojin.myapplication;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

    private ProgressDialog mProgressDialog;
    private int mContentLength;
    private long mCurrentLength;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    if (mContentLength <= 0) {
                        mProgressDialog.setProgress(0);
                        mTextView.setText(0);
                    } else {
                        int p = (int) (mCurrentLength * 100 / mContentLength);
                        mProgressDialog.setProgress(p);
                        mTextView.setText(p + "");
                    }
                    break;
                case 1:
                    Toast.makeText(MainActivity.this, "Down Finished!", Toast.LENGTH_LONG).show();
                    mProgressDialog.dismiss();
                    mProgressDialog = null;
                    break;
                case 2:
                    mProgressDialog.show();
                    break;
                default:
                    break;
            }
        }
    };
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.textView);
    }

    public void click(View view) {
        String url = "http://www.chinaums.com/static/ums2013/chinaums/app/download/ppplugin.apk";
        downLoadFile(url, new File(Environment.getExternalStorageDirectory(), url.substring(url.lastIndexOf("/") + 1)));
    }

    private void downLoadFile(final String url, final File destFile) {
        mProgressDialog = new ProgressDialog(this);
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgressDialog.setMax(100);
        mProgressDialog.incrementProgressBy(1);
        mProgressDialog.setProgress(0);

        new Thread(new Runnable() {
            @Override
            public void run() {

                mHandler.sendEmptyMessage(2);
                BufferedInputStream in = null;
                BufferedOutputStream out = null;
                HttpURLConnection conn = null;
                try {
                    conn = getHttpURLConnection(conn, url);

                    int times = 5;
                    while (conn.getResponseCode() != HttpURLConnection.HTTP_OK && times-- > 0) {
                        Log.e("tag", "----------ResponseCode: " + conn.getResponseCode()+", URL:" + url);
                        String url = conn.getHeaderField("Location");
                        conn = getHttpURLConnection(conn, url);
                        Log.e("tag", "----------NextURL:" + url);
                    }
                    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        mContentLength = conn.getContentLength();
                        in = new BufferedInputStream(conn.getInputStream());
                        out = new BufferedOutputStream(new FileOutputStream(destFile));
                        byte[] buffer = new byte[1024];
                        int len = 0;
                        mCurrentLength = 0;

                        while ((len = in.read(buffer)) != -1) {
                            out.write(buffer, 0, len);
                            mCurrentLength += len;
                            mHandler.sendEmptyMessage(0);
                        }
                        out.flush();

                        mHandler.sendEmptyMessage(1);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (conn != null) {
                        conn.disconnect();
                    }
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }

    @NonNull
    private HttpURLConnection getHttpURLConnection(HttpURLConnection conn, String url) throws IOException {
        conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setConnectTimeout(8000);
        conn.setReadTimeout(8000);
        conn.setInstanceFollowRedirects(false);//不支持重定向
        conn.connect();
        return conn;
    }
}
`

收藏

菜根谭 —— 洪应明 必读经典!

Android Part :

Android通用流行框架大全

框架

周趋势

Blog

VR

Android 开发程序员必备网站

基于Android 最新技术开发的APP合集

优秀电影

  • 赛德克巴莱
  • 窃听风暴
  • 第一滴血

Kotlin 协程

参考:https://mp.weixin.qq.com/s?__biz=MzIzMTYzOTYzNA==&mid=2247483875&idx=1&sn=b1b565f651ee1221d4bda19ab12009ce&chksm=e8a05ededfd7d7c878c1c483c577ec53bcf42ee4cb0fe5d13f29d12ff62a1e335c4afa616ffa#rd

一句话,有了协程,你的异步程序看起来就像同步代码一样。

V:View,关注处理视图的可视化及与用户交互
P:Presenter,关注业务处理

###在MVP模式里通常包含4个要素:
(1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);
(2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;
(3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);
(4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

###总结:

V:持有P的引用,项目规格不大,可以不使用P的接口
P:持有M、V的接口实现对象

**Note:** 
防止Activity或Fragment声明周期结束后,一般执行耗时操作的Presenter层因为持有对Activity或Fragment的强引用,导致内存泄漏。

**处理方法:**
1.  解除绑定关系,在V层生命周期的OnDestory()中,调用P层持有的V,将其置空,解除和P层的关联。
2.  为了弥补在特殊情况下,如系统突然回收内存,导致Activity的onStop、onDestory没有执行便被干掉,造成上一种方式解除绑定代码没有被执行,特还需要使用软引用或弱引用。


/**
 * code from Android源码设计模式
 */
public abstract class BasePresenter<T> {
    protected Reference<T> mViewRef;

    public void attachView(T view) {
        mViewRef = new WeakReference<T>(view);
    }

    protected T getView() {
        return mViewRef.get();
    }

    protected void detachView() {
        if (mViewRef != null) {
            mViewRef.clear();
            mViewRef = null;
        }
    }
}

public abstract class MVPBaseActivity<V, T extends BasePresenter<V>> extends AppCompatActivity {
    BasePresenter mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPresenter = createPresenter();
        mPresenter.attachView((V) this);
    }

    public abstract T createPresenter();

    @Override
    public void onDestroy() {
        mPresenter.detachView();
    }
}
|