首页 > 代码库 > 下载的管理类MyDownloadManager

下载的管理类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.itcast.googleplay10.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.itcast.googleplay10.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.itcast.googleplay10.utils.IOUtils;import cn.itcast.googleplay10.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 = http://www.mamicode.com/out.toByteArray();"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.itcast.googleplay10.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

下载的管理类MyDownloadManager