谷歌应用市场6
2015-11-03 17:32
246 查看
1.观察设计模式
1.观察者与被观察者2.观察进度的改变
3.自己重新定义被观察者,可以多暴露多个方法
(1)被观察者
// 被观察者 // 假设 具备当前的下载进度 public class DownloadManager { public interface Observer{ public void update(); public void updateState(); } List<Observer> observers=new ArrayList<DownloadManager.Observer>(); // 有内容发生了改变1 // 添加观察者 public void addObserver(Observer observer){ if(observer==null){ throw new RuntimeException(); } if(!observers.contains(observer)){ observers.add(observer); } } // 通知数据发生变化 public void notifyObservers(){ for(Observer observer:observers){ observer.update(); } } // 通知状态改变 public void notifyState(){ for(Observer observer:observers){ observer.updateState(); } } }
(2)观察者1
// 观察者 public class DetailView implements Observer { @Override public void update() { System.out.println("aaabbbccc"); } @Override public void updateState() { System.out.println("状态发生改变"); } }
(3)观察者2
// 观察者 public class DetailView2 implements Observer { //当被观察者数据发生变化的时候 调用该方法 @Override public void update(Observable observable, Object data) { System.out.println("爷爷观察到了你的变化"); } }
(4)MainActivity
public class MainActivity extends Activity { private DownloadManager downloadManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); downloadManager = new DownloadManager(); downloadManager.addObserver(new DetailView()); // 当被观察者 数据发生变化的时候 通知观察者 // downloadManager.addObserver(new DetailView2()); // 观察者 } public void click(View v){ downloadManager.notifyObservers();// 通知观察者 内容发生变化 } }
4.项目补充:下载被观察者
public class DownloadManager { /** 默认 */ 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_PAUSE = 3; /** 错误 */ public static final int STATE_ERROR = 4; /** 下载完成 */ public static final int STATE_DOWNLOED = 5; private static DownloadManager instance; private DownloadManager() { } /** 用于记录下载信息,如果是正式项目,需要持久化保存 */ private Map<Long, DownloadInfo> mDownloadMap = new ConcurrentHashMap<Long, DownloadInfo>(); /**用于记录所有下载的任务,方便取消下载时,能通过id找到该任务进行删除*/ private Map<Long,DownloadTask> mTaskMap=new ConcurrentHashMap<Long, DownloadManager.DownloadTask>(); private List<DownloadObserver> mObservers=new ArrayList<DownloadObserver>(); /** 注册观察者 */ public void registerObserver(DownloadObserver observer) { synchronized (mObservers) { if (!mObservers.contains(observer)) { mObservers.add(observer); } } } /** 反注册观察者 */ public void unRegisterObserver(DownloadObserver observer) { synchronized (mObservers) { if (mObservers.contains(observer)) { mObservers.remove(observer); } } } /** 当下载状态发送改变的时候回调 */ public void notifyDownloadStateChanged(DownloadInfo info) { synchronized (mObservers) { for (DownloadObserver observer : mObservers) { observer.onDownloadStateChanged(info); } } } /** 当下载进度发送改变的时候回调 */ public void notifyDownloadProgressed(DownloadInfo info) { synchronized (mObservers) { for (DownloadObserver observer : mObservers) { observer.onDownloadProgressed(info); } } } // 单例 public static synchronized DownloadManager getInstance() { if (instance == null) { instance = new DownloadManager(); } return instance; } public synchronized void download(AppInfo appInfo) { DownloadInfo info = mDownloadMap.get(appInfo.getId()); if (info == null) { info = DownloadInfo.clone(appInfo); mDownloadMap.put(appInfo.getId(), info);// 保存到集合中 } if (info.getDownloadState() == STATE_NONE || info.getDownloadState() == STATE_PAUSE || info.getDownloadState() == STATE_ERROR) { // 下载之前,把状态设置为STATE_WAITING, // 因为此时并没有产开始下载,只是把任务放入了线程池中, // 当任务真正开始执行时,才会改为STATE_DOWNLOADING info.setDownloadState(STATE_WAITING); // 通知更新界面 notifyDownloadStateChanged(info); DownloadTask task = new DownloadTask(info); mTaskMap.put(info.getId(), task); ThreadManager.creatDownLoadPool().execute(task); } } /** 安装应用 */ public synchronized void install(AppInfo appInfo) { stopDownload(appInfo); DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息 if (info != null) {// 发送安装的意图 Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.setDataAndType(Uri.parse("file://" + info.getPath()), "application/vnd.android.package-archive"); UIUtils.getContext().startActivity(installIntent); } notifyDownloadStateChanged(info); } /**暂停下载*/ public synchronized void pause(AppInfo appInfo){ stopDownload(appInfo); DownloadInfo info=mDownloadMap.get(appInfo.getId()); if(info!=null){// 修改下载状态 info.setDownloadState(STATE_PAUSE); notifyDownloadStateChanged(info); } } /** 取消下载,逻辑和暂停类似,只是需要删除已下载的文件 */ public synchronized void cancel(AppInfo appInfo) { stopDownload(appInfo); DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息 if (info != null) {// 修改下载状态并删除文件 info.setDownloadState(STATE_NONE); notifyDownloadStateChanged(info); info.setCurrentSize(0); File file = new File(info.getPath()); file.delete(); } } private void stopDownload(AppInfo appInfo) { DownloadTask task=mTaskMap.remove(appInfo.getId()); if(task!=null){ ThreadManager.creatDownLoadPool().cancel(task); } } public class DownloadTask implements Runnable { private DownloadInfo info; public DownloadTask(DownloadInfo info) { this.info = info; } @Override public void run() { info.setDownloadState(STATE_DOWNLOADING); notifyDownloadStateChanged(info); File file = new File(info.getPath());// 获取下载文件 HttpResult httpResult = null; InputStream stream = null; // 如果文件不存在, 或者进度为0,或者进度和文件长度不一致 重新下载 if (info.getCurrentSize() == 0 || !file.exists() || file.length() != info.getCurrentSize()) { info.setCurrentSize(0); file.delete(); httpResult = HttpHelper.download(HttpHelper.URL + "download?name=" + info.getUrl()); } else { // 不需要重新下载 // 文件存在且长度和进度相等,采用断点下载 httpResult = HttpHelper.download(HttpHelper.URL + "download?name=" + info.getUrl() + "&range=" + info.getCurrentSize()); } if (httpResult == null || (stream = httpResult.getInputStream()) == null) { info.setDownloadState(STATE_ERROR); notifyDownloadStateChanged(info); } else { FileOutputStream fos = null; try { fos = new FileOutputStream(file, true); int count = -1; byte[] buffer = new byte[1024]; while (((count = stream.read(buffer)) != -1) && info.getDownloadState() == STATE_DOWNLOADING) { fos.write(buffer, 0, count); fos.flush(); info.setCurrentSize(info.getCurrentSize()+count); notifyDownloadProgressed(info); } } catch (Exception e) { LogUtils.e(e);// 出异常后需要修改状态并删除文件 info.setDownloadState(STATE_ERROR); notifyDownloadStateChanged(info); info.setCurrentSize(0); file.delete(); } finally { IOUtils.close(fos); if (httpResult != null) { httpResult.close(); } } // 判断进度是否和App相等 if (info.getCurrentSize() == info.getAppSize()) { info.setDownloadState(STATE_DOWNLOED); notifyDownloadStateChanged(info); } else if (info.getDownloadState() == STATE_PAUSE) { notifyDownloadStateChanged(info); } else { info.setDownloadState(STATE_ERROR); notifyDownloadStateChanged(info); info.setCurrentSize(0); file.delete(); } } mTaskMap.remove(info.getId()); } } public interface DownloadObserver { public void onDownloadStateChanged(DownloadInfo info); public void onDownloadProgressed(DownloadInfo info); } public DownloadInfo getDownloadInfo(long id) { // TODO Auto-generated method stub return mDownloadMap.get(id); } }
2.总结
1.详情见PPT和完整代码2.自定义圆形进度条
框架
public class ProgressView extends View { public ProgressView(Context context) { super(context); } public ProgressView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ProgressView(Context context, AttributeSet attrs) { super(context, attrs); } // 绘制控件 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //canvas.drawBitmap(bitmap, left, top, paint); 把图片画进去,背景图片 /*oval 圆的模型 矩形 * startAngle 开始的角度 * sweepAngle 范围的角度 //不停修改这个 * useCenter 是否填充中间部分 * paint 画笔 */ //canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint); } }
3.完整代码
public class ProgressArc extends View { private final static int START_PROGRESS = -90; private static final int SET_PROGRESS_END_TIME = 1000; private static final float RATIO = 360f; public final static int PROGRESS_STYLE_NO_PROGRESS = -1; public final static int PROGRESS_STYLE_DOWNLOADING = 0; public final static int PROGRESS_STYLE_WAITING = 1; private int mDrawableForegroudResId; private Drawable mDrawableForegroud;//图片 private int mProgressColor;//进度条的颜色 private RectF mArcRect;//用于画圆形的区域 private Paint mPaint;//用户画进度条的画笔 private boolean mUserCenter = false; private OnProgressChangeListener mProgressChangeListener;//进度改变的监听 private float mStartProgress;//动画的起始进度 private float mCurrentProgress;//当前进度 private float mProgress;//目标进度 private float mSweep; private long mStartTime, mEndTime; private int mStyle = PROGRESS_STYLE_NO_PROGRESS; private int mArcDiameter; public ProgressArc(Context context) { super(context); int strokeWidth = UIUtils.dip2px(1); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(strokeWidth); mUserCenter = false; mArcRect = new RectF(); } public void setProgressChangeListener(OnProgressChangeListener listener) { mProgressChangeListener = listener; } public void seForegroundResource(int resId) { if (mDrawableForegroudResId == resId) { return; } mDrawableForegroudResId = resId; mDrawableForegroud = UIUtils.getDrawable(mDrawableForegroudResId); invalidateSafe(); } /** 设置直径 */ public void setArcDiameter(int diameter) { mArcDiameter = diameter; } /** 设置进度条的颜色 */ public void setProgressColor(int progressColor) { mProgressColor = progressColor; mPaint.setColor(progressColor); } public void setStyle(int style) { this.mStyle = style; if (mStyle == PROGRESS_STYLE_WAITING) { invalidateSafe(); } else { } } /** 设置进度,第二个参数是否采用平滑进度 */ public void setProgress(float progress, boolean smooth) { mProgress = progress; if (mProgress == 0) { mCurrentProgress = 0; } mStartProgress = mCurrentProgress; mStartTime = System.currentTimeMillis(); if (smooth) { mEndTime = SET_PROGRESS_END_TIME; } else { mEndTime = 0; } invalidateSafe(); } private void invalidateSafe() { if (UIUtils.isRunInMainThread()) { postInvalidate(); } else { invalidate(); } } /** 测量 */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = 0; int height = 0; int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) {//如果是精确的 width = widthSize; } else {//采用图片的大小 width = mDrawableForegroud == null ? 0 : mDrawableForegroud.getIntrinsicWidth(); if (widthMode == MeasureSpec.AT_MOST) { width = Math.min(width, widthSize); } } if (heightMode == MeasureSpec.EXACTLY) {//如果是精确的 height = heightSize; } else {//采用图片的大小 height = mDrawableForegroud == null ? 0 : mDrawableForegroud.getIntrinsicHeight(); if (heightMode == MeasureSpec.AT_MOST) { height = Math.min(height, heightSize); } } //计算出进度条的区域 mArcRect.left = (width - mArcDiameter) * 0.5f; mArcRect.top = (height - mArcDiameter) * 0.5f; mArcRect.right = (width + mArcDiameter) * 0.5f; mArcRect.bottom = (height + mArcDiameter) * 0.5f; setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { if (mDrawableForegroud != null) {//先把图片画出来 mDrawableForegroud.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); mDrawableForegroud.draw(canvas); } //再画进度 drawArc(canvas); } protected void drawArc(Canvas canvas) { if (mStyle == PROGRESS_STYLE_DOWNLOADING || mStyle == PROGRESS_STYLE_WAITING) { float factor; long currentTime = System.currentTimeMillis(); if (mProgress == 100) { factor = 1; } else { if (currentTime - mStartTime < 0) { factor = 0; } else if (currentTime - mStartTime > mEndTime) { factor = 1; } else { factor = (currentTime - mStartTime) / (float) mEndTime; } } mPaint.setColor(mProgressColor); mCurrentProgress = mStartProgress + factor * (mProgress - mStartProgress); mSweep = mCurrentProgress * RATIO; canvas.drawArc(mArcRect, START_PROGRESS, mSweep, mUserCenter, mPaint); if (factor != 1 && mStyle == PROGRESS_STYLE_DOWNLOADING) { invalidate(); } if (mCurrentProgress > 0) { notifyProgressChanged(mCurrentProgress); } } } private void notifyProgressChanged(float currentProgress) { if (mProgressChangeListener != null) { mProgressChangeListener.onProgressChange(currentProgress); } } public static interface OnProgressChangeListener { public void onProgressChange(float smoothProgress); } }
4.应用详情内的进度条修改样式
<item type="id" name="detail_progress"></item> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@android:id/background"> <bitmap android:src="@drawable/progress_bg2" /> </item> <item android:id="@android:id/secondaryProgress"> <bitmap android:src="@drawable/progress_bg2" /> </item> <item android:id="@android:id/progress"> <bitmap android:src="@drawable/process_normal2" /> </item> </layer-list>
补充
1.收藏下载分享(1)界面
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/bottom_layout" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/bottom_favorites" android:layout_width="68dp" android:layout_height="38dp" android:layout_alignParentLeft="true" android:layout_margin="6dp" android:background="@drawable/detail_btn" android:gravity="center" android:textColor="#ffffff" android:textSize="16dp" /> <Button android:id="@+id/bottom_share" android:layout_width="68dp" android:layout_height="38dp" android:layout_alignParentRight="true" android:layout_margin="6dp" android:background="@drawable/detail_btn" android:gravity="center" android:textColor="#ffffff" android:textSize="16dp" /> <FrameLayout android:id="@+id/progress_layout" android:layout_width="match_parent" android:layout_height="38dp" android:layout_centerVertical="true" android:layout_toLeftOf="@id/bottom_share" android:layout_toRightOf="@id/bottom_favorites" > <ProgressBar android:background="@drawable/progress_bg" android:id="@+id/pb_load_process" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:progressDrawable="@drawable/progress_drawable" android:visibility="invisible" /> <TextView android:id="@+id/tv_load_process" android:layout_width="match_parent" android:layout_height="match_parent" android:text="暂停" android:textColor="#ffffff" android:textSize="18sp" android:gravity="center"/> </FrameLayout> <Button android:id="@+id/progress_btn" android:layout_width="match_parent" android:layout_height="38dp" android:layout_centerVertical="true" android:layout_toLeftOf="@id/bottom_share" android:layout_toRightOf="@id/bottom_favorites" android:background="@drawable/progress_btn" android:gravity="center" android:textColor="#ffffff" android:textSize="18dp" > </Button> </RelativeLayout>
(2)progress_drawable 图层
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@android:id/background"> <bitmap android:src="@drawable/progress_bg2" /> </item> <item android:id="@android:id/secondaryProgress"> <bitmap android:src="@drawable/progress_bg2" /> </item> <item android:id="@android:id/progress"> <bitmap android:src="@drawable/process_normal2" /> </item> </layer-list>
2.DownloadManager
public class DownloadManager { /** 默认 */ 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_PAUSE = 3; /** 错误 */ public static final int STATE_ERROR = 4; /** 下载完成 */ public static final int STATE_DOWNLOED = 5; private static DownloadManager instance; private DownloadManager() { } /** 用于记录下载信息,如果是正式项目,需要持久化保存 */ private Map<Long, DownloadInfo> mDownloadMap = new ConcurrentHashMap<Long, DownloadInfo>(); /**用于记录所有下载的任务,方便取消下载时,能通过id找到该任务进行删除*/ private Map<Long,DownloadTask> mTaskMap=new ConcurrentHashMap<Long, DownloadManager.DownloadTask>(); private List<DownloadObserver> mObservers=new ArrayList<DownloadObserver>(); /** 注册观察者 */ public void registerObserver(DownloadObserver observer) { synchronized (mObservers) { if (!mObservers.contains(observer)) { mObservers.add(observer); } } } /** 反注册观察者 */ public void unRegisterObserver(DownloadObserver observer) { synchronized (mObservers) { if (mObservers.contains(observer)) { mObservers.remove(observer); } } } /** 当下载状态发送改变的时候回调 */ public void notifyDownloadStateChanged(DownloadInfo info) { synchronized (mObservers) { for (DownloadObserver observer : mObservers) { observer.onDownloadStateChanged(info); } } } /** 当下载进度发送改变的时候回调 */ public void notifyDownloadProgressed(DownloadInfo info) { synchronized (mObservers) { for (DownloadObserver observer : mObservers) { observer.onDownloadProgressed(info); } } } // 单例 public static synchronized DownloadManager getInstance() { if (instance == null) { instance = new DownloadManager(); } return instance; } public synchronized void download(AppInfo appInfo) { DownloadInfo info = mDownloadMap.get(appInfo.getId()); if (info == null) { info = DownloadInfo.clone(appInfo); mDownloadMap.put(appInfo.getId(), info);// 保存到集合中 } if (info.getDownloadState() == STATE_NONE || info.getDownloadState() == STATE_PAUSE || info.getDownloadState() == STATE_ERROR) { // 下载之前,把状态设置为STATE_WAITING, // 因为此时并没有产开始下载,只是把任务放入了线程池中, // 当任务真正开始执行时,才会改为STATE_DOWNLOADING info.setDownloadState(STATE_WAITING); // 通知更新界面 notifyDownloadStateChanged(info); DownloadTask task = new DownloadTask(info); mTaskMap.put(info.getId(), task); ThreadManager.creatDownLoadPool().execute(task); } } /** 安装应用 */ public synchronized void install(AppInfo appInfo) { stopDownload(appInfo); DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息 if (info != null) {// 发送安装的意图 Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.setDataAndType(Uri.parse("file://" + info.getPath()), "application/vnd.android.package-archive"); UIUtils.getContext().startActivity(installIntent); } notifyDownloadStateChanged(info); } /**暂停下载*/ public synchronized void pause(AppInfo appInfo){ stopDownload(appInfo); DownloadInfo info=mDownloadMap.get(appInfo.getId()); if(info!=null){// 修改下载状态 info.setDownloadState(STATE_PAUSE); notifyDownloadStateChanged(info); } } /** 取消下载,逻辑和暂停类似,只是需要删除已下载的文件 */ public synchronized void cancel(AppInfo appInfo) { stopDownload(appInfo); DownloadInfo info = mDownloadMap.get(appInfo.getId());// 找出下载信息 if (info != null) {// 修改下载状态并删除文件 info.setDownloadState(STATE_NONE); notifyDownloadStateChanged(info); info.setCurrentSize(0); File file = new File(info.getPath()); file.delete(); } } private void stopDownload(AppInfo appInfo) { DownloadTask task=mTaskMap.remove(appInfo.getId()); if(task!=null){ ThreadManager.creatDownLoadPool().cancel(task); } } public class DownloadTask implements Runnable { private DownloadInfo info; public DownloadTask(DownloadInfo info) { this.info = info; } @Override public void run() { info.setDownloadState(STATE_DOWNLOADING); notifyDownloadStateChanged(info); File file = new File(info.getPath());// 获取下载文件 HttpResult httpResult = null; InputStream stream = null; // 如果文件不存在, 或者进度为0,或者进度和文件长度不一致 重新下载 if (info.getCurrentSize() == 0 || !file.exists() || file.length() != info.getCurrentSize()) { info.setCurrentSize(0); file.delete(); httpResult = HttpHelper.download(HttpHelper.URL + "download?name=" + info.getUrl()); } else { // 不需要重新下载 // 文件存在且长度和进度相等,采用断点下载 httpResult = HttpHelper.download(HttpHelper.URL + "download?name=" + info.getUrl() + "&range=" + info.getCurrentSize()); } if (httpResult == null || (stream = httpResult.getInputStream()) == null) { info.setDownloadState(STATE_ERROR); notifyDownloadStateChanged(info); } else { FileOutputStream fos = null; try { fos = new FileOutputStream(file, true); int count = -1; byte[] buffer = new byte[1024]; while (((count = stream.read(buffer)) != -1) && info.getDownloadState() == STATE_DOWNLOADING) { fos.write(buffer, 0, count); fos.flush(); info.setCurrentSize(info.getCurrentSize()+count); notifyDownloadProgressed(info); } } catch (Exception e) { LogUtils.e(e);// 出异常后需要修改状态并删除文件 info.setDownloadState(STATE_ERROR); notifyDownloadStateChanged(info); info.setCurrentSize(0); file.delete(); } finally { IOUtils.close(fos); if (httpResult != null) { httpResult.close(); } } // 判断进度是否和App相等 if (info.getCurrentSize() == info.getAppSize()) { info.setDownloadState(STATE_DOWNLOED); notifyDownloadStateChanged(info); } else if (info.getDownloadState() == STATE_PAUSE) { notifyDownloadStateChanged(info); } else { info.setDownloadState(STATE_ERROR); notifyDownloadStateChanged(info); info.setCurrentSize(0); file.delete(); } } mTaskMap.remove(info.getId()); } } public interface DownloadObserver { public void onDownloadStateChanged(DownloadInfo info); public void onDownloadProgressed(DownloadInfo info); } public DownloadInfo getDownloadInfo(long id) { // TODO Auto-generated method stub return mDownloadMap.get(id); } }
相关文章推荐
- phpMyAdmin对外开放
- Junit 源码剖析(二)
- 我在项目产品中的常用工具
- nyoj--68--三点顺序(数学)
- STM32之CAN ---CAN ID过滤器分析
- XMPP
- 前端标签命名规范
- nyoj--68--三点顺序(数学)
- 安装Maven后提示找不到JDK的错误 。The Maven Integration requires that Eclipse be running in a JDK
- word在试图打开时遇到错误
- 如何设计线程安全的类 分布式系统需要考虑的问题
- LNMP(linux+nginx+mysql+php)服务器环境配置
- 安装Google Chrome浏览器
- ArrayList源码浅析
- Alpha阶段个人贡献分及转会人员确定
- 打印数字的二进制 利用数组输出大数据
- 嘎嘎嘎嘎
- 乱序不重复整数数组求中位数
- Week2-1parts of speech
- 路由器TP-LINK设置花生壳域名