下载的管理类MyDownloadManager

import android.content.Intent;
import android.net.Uri;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * 下载的管理类
 */

public class MyDownloadManager {

    public static final int STATE_NONE = 0;//未下载
    public static final int STATE_WAITING = 1;//等待中
    public static final int STATE_DOWNLOADING= 2;//下载中
    public static final int STATE_PAUSED= 3;//下载暂停
    public static final int STATE_SUCCESS = 4;//下载成功
    public static final int STATE_ERROR = 5;//下载失败

    private MyDownloadManager() {}

    private static MyDownloadManager instance;

    public synchronized  static MyDownloadManager getInstance() {
        if (instance == null) {
            instance = new MyDownloadManager();
        }
        return instance;
    }

    public HashMap<String, DownloadInfo> mSavedDownloadInfo = new HashMap<>();
    public HashMap<String, DownloadTask> mSavedDownloadTask = new HashMap<>();

    //对于AppInfo来说,downloadUrl、size、id、name、packageName
    //存在本地的路径,当前下载的状态,当前下载的进度
    public void startDownload(AppInfo info) {
        //需要将downloadInfo缓存起来,以便我们继续下载的时候来使用
        DownloadInfo downloadInfo = mSavedDownloadInfo.get(info.id);//DownloadInfo.createDownloadInfoFromAppInfo(info);
        if(downloadInfo == null) {
            downloadInfo = DownloadInfo.createDownloadInfoFromAppInfo(info);
            mSavedDownloadInfo.put(info.id, downloadInfo);
        }

        //开始真正的下载了
        DownloadTask task = new DownloadTask(downloadInfo);
        mSavedDownloadTask.put(info.id, task);
        downloadInfo.currentState = MyDownloadManager.STATE_WAITING;
        notifyDownloadStateChanged(downloadInfo);
        MyThreadPoolManager.getInstance().execute(task);

    }

    public void pauseDownload(AppInfo data) {
        //暂停下载
        DownloadInfo downloadInfo = mSavedDownloadInfo.get(data.id);
        downloadInfo.currentState = STATE_PAUSED;

        //如果有一个任务已经丢到了线程池中,但是run方法还没有执行
        //将任务从等待区域中移除
        DownloadTask task = mSavedDownloadTask.get(data.id);
        MyThreadPoolManager.getInstance().cancle(task);

    }

    public void installApk(AppInfo data) {
        DownloadInfo downloadInfo = mSavedDownloadInfo.get(data.id);
        //打开系统的安装界面
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(
                Uri.fromFile(new File(downloadInfo.filePath)),
                "application/vnd.android.package-archive");
        UiUtils.getContext().startActivity(intent);
    }

    class DownloadTask implements  Runnable {

        private DownloadInfo downloadInfo;

        public DownloadTask(DownloadInfo downloadInfo) {
            this.downloadInfo = downloadInfo;
        }

        @Override
        public void run() {
            FileOutputStream fos = null;
            try {
                //由于是由线程池来进行管理的,所以只有走到了run方法才代表这个任务被线程池中的线程执行
                downloadInfo.currentState = MyDownloadManager.STATE_DOWNLOADING;
                notifyDownloadStateChanged(downloadInfo);
                //区分一下是否是第一次下载
                File downloadFile = new File(downloadInfo.filePath);
                //下载apk
                String url = "";
                if(!downloadFile.exists()
                        ||downloadInfo.currentPosition==0
                        ||(downloadInfo.currentPosition!=0&&downloadInfo.currentPosition != downloadFile.length())) {
                    //第一次下载
                    downloadFile.delete();
                    downloadInfo.currentPosition = 0;
                    url = HttpHelper.URL + "download?name=" + downloadInfo.downloadUrl;
                } else {
                    //代表的是断电下载,告诉服务器从这个文件的哪个位置开始给我吐数据
                    url = HttpHelper.URL + "download?name=" + downloadInfo.downloadUrl+"&range=" + downloadInfo.currentPosition;
                }


                HttpHelper.HttpResult httpResult = HttpHelper.download(url);
                if(httpResult != null) {
                    //获取文件的输入流
                    InputStream inputStream = httpResult.getInputStream();
                    if(inputStream != null) {
                        //第二个参数必须传true,否则的话,就会覆盖之前已经下载好的那一小部分文件
                        fos = new FileOutputStream(downloadFile,true);
                        byte[] buffer = new byte[1024];//30
                        int length = 0;
                        while((length = inputStream.read(buffer)) != -1 && downloadInfo.currentState == STATE_DOWNLOADING) {
                            fos.write(buffer, 0, length);
                            downloadInfo.currentPosition = downloadInfo.currentPosition + length;
                            notifyDownloadProgressChanged(downloadInfo);
                            fos.flush();
                        }

                        //下载完成
                        //判断一下下载是否成功
                        long serverFileSize = Long.parseLong(downloadInfo.size);
                        long localFileSize = downloadInfo.currentPosition;
                        if(serverFileSize == localFileSize) {
                            //下载成功
                            downloadInfo.currentState = STATE_SUCCESS;
                            notifyDownloadStateChanged(downloadInfo);
                        } else {

                            if(downloadInfo.currentState == STATE_PAUSED) {
                                //2、下载暂停
                                downloadInfo.currentState = STATE_PAUSED;
                                notifyDownloadStateChanged(downloadInfo);
                            } else {
                                //1、下载失败
                                downloadInfo.currentState = STATE_ERROR;
                                notifyDownloadStateChanged(downloadInfo);
                            }
                        }

                    } else {
                        //此时代表服务器访问成功,但是服务器找不到你所要下载的文件
                        //下载失败
                        downloadInfo.currentState = STATE_ERROR;
                        notifyDownloadStateChanged(downloadInfo);
                    }

                } else {
                    //下载失败
                    downloadInfo.currentState = STATE_ERROR;
                    notifyDownloadStateChanged(downloadInfo);
                }

            } catch (Exception e) {
                downloadInfo.currentState = STATE_ERROR;
                notifyDownloadStateChanged(downloadInfo);
            } finally {
                IOUtils.close(fos);
            }

        }
    }

    public interface  DownloadObserver{
        public void onDownloadStateChanged(DownloadInfo downloadInfo);
        public void onDownloadProgressChanged(DownloadInfo downloadInfo);
    }

    private ArrayList<DownloadObserver> observers = new ArrayList<>();

    public void addDownloadObserver(DownloadObserver observer) {
        if(observer != null && !observers.contains(observer)) {
            observers.add(observer);
        }
    }

    private void notifyDownloadStateChanged(DownloadInfo downloadInfo) {
        for(int i=0;i<observers.size();i++) {
            DownloadObserver downloadObserver = observers.get(i);
            downloadObserver.onDownloadStateChanged(downloadInfo);
        }
    }

    private void notifyDownloadProgressChanged(DownloadInfo downloadInfo) {
        for(int i=0;i<observers.size();i++) {
            DownloadObserver downloadObserver = observers.get(i);
            downloadObserver.onDownloadProgressChanged(downloadInfo);
        }
    }

}

DownloadIofo.java

import android.os.Environment;
import java.io.File;
import cn.loaderman.manager.MyDownloadManager;

public class DownloadInfo {

    public String downloadUrl;
    public String id;
    public String name;
    public String packageName;
    public String size;
    public long currentPosition;//当前下载的位置
    public int currentState;//下载的状态
    public String filePath;//下载存储的本地路径


    public static DownloadInfo createDownloadInfoFromAppInfo(AppInfo appInfo) {
        DownloadInfo downloadInfo = new DownloadInfo();
        downloadInfo.id = appInfo.id;
        downloadInfo.downloadUrl = appInfo.downloadUrl;
        downloadInfo.name = appInfo.name;
        downloadInfo.packageName = appInfo.packageName;
        downloadInfo.size = appInfo.size;
        downloadInfo.currentState = MyDownloadManager.STATE_NONE;
        downloadInfo.currentPosition = 0;
        downloadInfo.filePath = getFilePath(appInfo.name);//   /sdcard/GooglePlay10/xxx.apk
        return downloadInfo;
    }

    public static String getFilePath(String name) {
        File rootDir = Environment.getExternalStorageDirectory();
        File appDir = new File(rootDir, "MyFile");
        if(!appDir.exists()||appDir.isFile()) {
            if(appDir.mkdirs()) {

            } else {
                return null;
            }
        }
        File apkFile = new File(appDir, name + ".apk");
        return apkFile.getAbsolutePath();
    }

}

 AppInfo.java

package cn.loaderman.bean;

import java.io.Serializable;
import java.util.ArrayList;



public class AppInfo {

    public String des;
    public String downloadUrl;
    public String iconUrl;
    public String id;
    public String name;
    public String packageName;
    public String size;
    public String stars;
    public String author;
    public String date;
    public String downloadNum;
    public ArrayList<SafeInfo> safe;
    public ArrayList<String> screen;
    public String version;
}

 SafeInfo.java

public class SafeInfo {

    public String safeDes;
    public String safeDesColor;
    public String safeDesUrl;
    public String safeUrl;
}

 httpHelper.java

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.SyncBasicHttpContext;

import android.util.Log;

import cn.loaderman.utils.IOUtils;
import cn.loaderman.utils.StringUtils;


public class HttpHelper {
	
	public static final String TAG = "HttpHelper";

	//127.0.0.1---> localhost
	public static final String URL = "http://127.0.0.1:8090/";

	/** get请求,获取返回字符串内容 */
	public static HttpResult get(String url) {
		HttpGet httpGet = new HttpGet(url);
		return execute(url, httpGet);
	}

	/** post请求,获取返回字符串内容 */
	public static HttpResult post(String url, byte[] bytes) {
		HttpPost httpPost = new HttpPost(url);
		ByteArrayEntity byteArrayEntity = new ByteArrayEntity(bytes);
		httpPost.setEntity(byteArrayEntity);
		return execute(url, httpPost);
	}

	/** 下载 */
	public static HttpResult download(String url) {
		HttpGet httpGet = new HttpGet(url);
		return execute(url, httpGet);
	}

	/** 执行网络访问 */
	private static HttpResult execute(String url, HttpRequestBase requestBase) {
		boolean isHttps = url.startsWith("https://");//判断是否需要采用https
		AbstractHttpClient httpClient = HttpClientFactory.create(isHttps);
		HttpContext httpContext = new SyncBasicHttpContext(new BasicHttpContext());
		HttpRequestRetryHandler retryHandler = httpClient.getHttpRequestRetryHandler();//获取重试机制
		int retryCount = 0;
		boolean retry = true;
		while (retry) {
			try {
				HttpResponse response = httpClient.execute(requestBase, httpContext);//访问网络
				if (response != null) {
					return new HttpResult(response, httpClient, requestBase);
				}
			} catch (Exception e) {
				IOException ioException = new IOException(e.getMessage());
				retry = retryHandler.retryRequest(ioException, ++retryCount, httpContext);//把错误异常交给重试机制,以判断是否需要采取从事
				Log.e(TAG,e.getMessage());
			}
		}
		return null;
	}

	/** http的返回结果的封装,可以直接从中获取返回的字符串或者流 */
	public static class HttpResult {
		private HttpResponse mResponse;
		private InputStream mIn;
		private String mStr;
		private HttpClient mHttpClient;
		private HttpRequestBase mRequestBase;

		public HttpResult(HttpResponse response, HttpClient httpClient, HttpRequestBase requestBase) {
			mResponse = response;
			mHttpClient = httpClient;
			mRequestBase = requestBase;
		}

		public int getCode() {
			StatusLine status = mResponse.getStatusLine();
			return status.getStatusCode();
		}

		/** 从结果中获取字符串,一旦获取,会自动关流,并且把字符串保存,方便下次获取 */
		public String getString() {
			if (!StringUtils.isEmpty(mStr)) {
				return mStr;
			}
			InputStream inputStream = getInputStream();
			ByteArrayOutputStream out = null;
			if (inputStream != null) {
				try {
					out = new ByteArrayOutputStream();
					byte[] buffer = new byte[1024 * 4];
					int len = -1;
					while ((len = inputStream.read(buffer)) != -1) {
						out.write(buffer, 0, len);
					}
					byte[] data = out.toByteArray();
					mStr = new String(data, "utf-8");
				} catch (Exception e) {
					Log.e(TAG,e.getMessage());
				} finally {
					IOUtils.close(out);
					close();
				}
			}
			return mStr;
		}

		/** 获取流,需要使用完毕后调用close方法关闭网络连接 */
		public InputStream getInputStream() {
			if (mIn == null && getCode() < 300) {
				HttpEntity entity = mResponse.getEntity();
				try {
					mIn = entity.getContent();
				} catch (Exception e) {
					Log.e(TAG,e.getMessage());
				}
			}
			return mIn;
		}

		/** 关闭网络连接 */
		public void close() {
			if (mRequestBase != null) {
				mRequestBase.abort();
			}
			IOUtils.close(mIn);
			if (mHttpClient != null) {
				mHttpClient.getConnectionManager().closeExpiredConnections();
			}
		}
	}
}

 HttpClientFactory.java

import org.apache.http.*;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.*;
import java.util.zip.GZIPInputStream;

public class HttpClientFactory {
	/** http请求最大并发连接数 */
	private static final int MAX_CONNECTIONS = 10;
	/** 超时时间 */
	private static final int TIMEOUT = 10 * 1000;
	/** 缓存大小 */
	private static final int SOCKET_BUFFER_SIZE = 8 * 1024; // 8KB
	/** 错误尝试次数,错误异常表请在RetryHandler添加 */
	private static final int MAX_RETRIES = 5;
	private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
	private static final String ENCODING_GZIP = "gzip";

	public static DefaultHttpClient create(boolean isHttps) {
		HttpParams params = createHttpParams();
		DefaultHttpClient httpClient = null;
		if (isHttps) {
			// 支持http与https
			SchemeRegistry schemeRegistry = new SchemeRegistry();
			schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
			// ThreadSafeClientConnManager线程安全管理类
			ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
			httpClient = new DefaultHttpClient(cm, params);
		} else {
			httpClient = new DefaultHttpClient(params);
		}
		return httpClient;
	}

	private static HttpParams createHttpParams() {
		final HttpParams params = new BasicHttpParams();
		// 设置是否启用旧连接检查,默认是开启的。关闭这个旧连接检查可以提高一点点性能,但是增加了I/O错误的风险(当服务端关闭连接时)。
		// 开启这个选项则在每次使用老的连接之前都会检查连接是否可用,这个耗时大概在15-30ms之间
		HttpConnectionParams.setStaleCheckingEnabled(params, false);
		HttpConnectionParams.setConnectionTimeout(params, TIMEOUT);// 设置链接超时时间
		HttpConnectionParams.setSoTimeout(params, TIMEOUT);// 设置socket超时时间
		HttpConnectionParams.setSocketBufferSize(params, SOCKET_BUFFER_SIZE);// 设置缓存大小
		HttpConnectionParams.setTcpNoDelay(params, true);// 是否不使用延迟发送(true为不延迟)
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); // 设置协议版本
		HttpProtocolParams.setUseExpectContinue(params, true);// 设置异常处理机制
		HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);// 设置编码
		HttpClientParams.setRedirecting(params, false);// 设置是否采用重定向

		ConnManagerParams.setTimeout(params, TIMEOUT);// 设置超时
		ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(MAX_CONNECTIONS));// 多线程最大连接数
		ConnManagerParams.setMaxTotalConnections(params, 10); // 多线程总连接数
		return params;
	}

	

	/** 当服务器返回的数据是以Gzip压缩的过后的数据,填充Response返回的实体数据 (Description),则返回GZIP解压流 */
	private static class InflatingEntity extends HttpEntityWrapper {
		public InflatingEntity(HttpEntity wrapped) {
			super(wrapped);
		}

		@Override
		public InputStream getContent() throws IOException {
			return new GZIPInputStream(wrappedEntity.getContent());
		}

		// 因为数据是压缩数据,所以实际长度无法估计,可以返回-1
		@Override
		public long getContentLength() {
			return -1;
		}
	}

	/** 自定义的安全套接字协议的实现,目前采用默认的,未使用到 */
	private static class SSLSocketFactoryEx extends SSLSocketFactory {
		// 此类的实例表示安全套接字协议的实现,它充当用于安全套接字工厂或 SSLEngine 的工厂。用可选的一组密钥和信任管理器及安全随机字节源初始化此类。
		SSLContext sslContext = SSLContext.getInstance("TLS");

		public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
			super(truststore);
			// TrustManager负责管理做出信任决定时使用的的信任材料,也负责决定是否接受同位体提供的凭据。
			// X509TrustManager此接口的实例管理使用哪一个 X509 证书来验证远端的安全套接字。决定是根据信任的证书授权、证书撤消列表、在线状态检查或其他方式做出的。
			TrustManager tm = new X509TrustManager() {
				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;// 返回受验证同位体信任的认证中心的数组。
				}

				@Override
				public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
					// 给出同位体提供的部分或完整的证书链,构建到可信任的根的证书路径,并且返回是否可以确认和信任将其用于基于验证类型的客户端 SSL 验证。
				}

				@Override
				public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
					// 给出同位体提供的部分或完整的证书链,构建到可信任的根的证书路径,并且返回是否可以确认和信任将其用于基于验证类型的服务器 SSL 验证。
				}
			};
			sslContext.init(null, new TrustManager[]{tm}, null);
		}

		@Override
		public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
			return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
		}

		@Override
		public Socket createSocket() throws IOException {
			return sslContext.getSocketFactory().createSocket();
		}
	}
}

 IOutils.java

import java.io.Closeable;
import java.io.IOException;

import android.util.Log;

public class IOUtils {

	public static final String TAG = "IOUtils";

	/** 关闭流 */
	public static boolean close(Closeable io) {
		if (io != null) {
			try {
				io.close();
			} catch (IOException e) {
				Log.e(TAG, e.getMessage());
			}
		}
		return true;
	}
}

 UiUtils.java

package cn.loaderman.utils;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Toast;

import java.util.Random;

/**
 * 处理和UI操作相关的工具类
 */

public class UiUtils {

    //获取全局Context对象
    public static Context getContext() {
        return MyApplication.instance.context;
    }

    //获取主线程的Handler对象
    public static Handler getMainThreadHandler() {
        return MyApplication.instance.handler;
    }

    //获取主线程的线程id
    public static int getMainThreadId() {
        return MyApplication.instance.mainThreadId;
    }

    //获取字符串
    public static String getString(int resId) {
        return getContext().getResources().getString(resId);
    }

    //获取字符串数组
    public static String[] getStringArray(int resId) {
        return getContext().getResources().getStringArray(resId);
    }

    //获取drawable
    public static Drawable getDrawable(int resId) {
        return getContext().getResources().getDrawable(resId);
    }

    public static int getColor(int resId) {
        return getContext().getResources().getColor(resId);
    }

    //产生随机的颜色值  90~230
    public static int getRandomColor() {
        Random random= new Random();
        int red =  90 + random.nextInt(141);;
        int green= 90 + random.nextInt(141);;
        int blue=  90 + random.nextInt(141);;
        int color = Color.rgb(red, green, blue);
        return color;
    }
    //获取文字大小   16~25
    public static int getRandomTextSize() {
        Random random= new Random();
        return 16+random.nextInt(10);
    }

    //获取颜色的状态选择器
    public static ColorStateList getColorStateList(int resId) {
        return getContext().getResources().getColorStateList(resId);
    }

    public static int getDimen(int resId) {
        return getContext().getResources().getDimensionPixelSize(resId);
    }

    //dip2px
    public static int dip2px(int dip) {
        //屏幕密度
        float density = getContext().getResources().getDisplayMetrics().density;
        return (int) (dip * density + 0.5f);
    }

    //px2dip
    public static int px2dip(int px) {
        //屏幕密度
        float density = getContext().getResources().getDisplayMetrics().density;
        return (int) (px/density + 0.5f);
    }


    public static View inflateView(int resId) {
        return View.inflate(getContext(), resId, null);
    }

    public static void toast(String msg) {
        Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
    }
    //判断是否是在主线程
    public static boolean isRunOnUiThread() {
        //1、获取当前线程的id
        int currentThreadId = android.os.Process.myTid();
        //2、获取主线程的id
        int mainThreadId = getMainThreadId();
        //3、做比较
        return currentThreadId == mainThreadId;
    }

    /**
     * 保证r这个任务一定是在主线程中执行
     *
     * Process:进程
     * Thread:线程
     * Runnable:任务
     *
     * @param r
     */
    public static void runOnUiThread(Runnable r) {
        if (isRunOnUiThread()) {
            //主线程
            //new Thread(r).start();
            r.run();
        } else {
            //子线程
            getMainThreadHandler().post(r);//将任务r丢到了主线程的消息队列
        }
    }

    //代码中创建shape标签对应的对象
    public static GradientDrawable getShape(int radius,int color) {
        GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setShape(GradientDrawable.RECTANGLE);
        gradientDrawable.setCornerRadius(radius);
        gradientDrawable.setColor(color);
        return gradientDrawable;
    }
    //代码中获取一个状态选择器  对应的类StateListDrawable
    public static StateListDrawable getSelector(Drawable pressedDrawable,Drawable normalDrawable) {
        StateListDrawable stateListDrawable = new StateListDrawable();
        stateListDrawable.addState(new int[]{android.R.attr.state_pressed},pressedDrawable);
        stateListDrawable.addState(new int[]{},normalDrawable);
        return stateListDrawable;
    }

    public static int getScreenWidth() {
        DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
        return displayMetrics.widthPixels;
    }

}

 StringUitls.java

public class StringUtils {
	/** 判断字符串是否有值,如果为null或者是空字符串或者只有空格或者为"null"字符串,则返回true,否则则返回false */
	public static boolean isEmpty(String value) {
		if (value != null && !"".equalsIgnoreCase(value.trim()) && !"null".equalsIgnoreCase(value.trim())) {
			return false;
		} else {
			return true;
		}
		//"null"
		//null
		
	}
}

 MyApplication.java

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;

import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;

import java.util.ArrayList;

/**
 * 1、生命周期长
 * 2、单实例
 * 3、onCreate方法可以简单的认为是一个应用程序的入口,onCreate是运行在主线程中
 *
 * 问题:onCreate这个方法只执行一次么?
 *
 * 注意事项:需要清单文件中注册
 */

public class MyApplication extends Application {

    public  Context context;
    public  Handler handler;
    public  int mainThreadId;

    public static MyApplication instance;

    public AppInfo appInfo;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        //Context 获取全局的context对象    new出一个View,加载布局文件,Toast
        context = getApplicationContext();

        //线程间的通信
        //handler.sendMessage:发送一个消息到消息队列
        //主线程有主线程的消息队列,子线程有子线程的消息队列
        //到底发送到哪一个线程的消息队列,得看handler维护的是哪个线程的消息队列
        //指定Handler维护的是主线程消息队列的方式:1、2、
        handler = new Handler();
        /*new Thread(new Runnable() {
            @Override
            public void run() {
                Handler mHandler = new Handler(Looper.getMainLooper());
            }
        }).start();*/

        //判断当前线程是主线程还是子线程
        mainThreadId = Process.myTid();

        initImageLoader(getApplicationContext());
    }

    private ArrayList<Activity> activityArrayList = new ArrayList<>();

    public void addActivity(Activity activity) {
        activityArrayList.add(activity);
    }

    public void removeActivity(Activity activity) {
        activityArrayList.remove(activity);
    }

    public static void initImageLoader(Context context) {
        // This configuration tuning is custom. You can tune every option, you may tune some of them,
        // or you can create default configuration by
        //  ImageLoaderConfiguration.createDefault(this);
        // method.
        ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context);
        config.threadPriority(Thread.NORM_PRIORITY - 2);
        config.denyCacheImageMultipleSizesInMemory();
        config.diskCacheFileNameGenerator(new Md5FileNameGenerator());
        config.diskCacheSize(50 * 1024 * 1024); // 50 MiB
        config.tasksProcessingOrder(QueueProcessingType.LIFO);
        config.writeDebugLogs(); // Remove for release app
        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(config.build());
    }
}

 导入org.apache.http.legacy.jar

原文地址:https://www.cnblogs.com/loaderman/p/6822180.html