Android编程思想,面向对象程序设计第六篇——封装(下)功能模块化,MVC分离
来源:互联网 发布:淘宝用户名字怎么改 编辑:程序博客网 时间:2024/04/26 06:14
上一节讲到了布局模块化,在实际开发中还有一个非常重要的是功能模块化。特别是团队开发的情况下,如果你没有进行模块化处理而是直接把某个功能的实现写在
Activity里面的话,时间长了发现很多都是重复性开发。明明同一个功能,却出现了你在你的Activity写你的实现方法,他在他的Activity写他的实现方法,浪费了大把时间。而且一旦这个功能点需要修改的时候,需要同时修改非常多的逻辑代码,还不一定都改的对。
所以正确的作法是把功能点封装载一个专门的类里面,这个类可以用接口和方法提供输入输出就可以了。这就是所谓的MVC。M是model负责处理数据逻辑,V是视图
负责处理界面,C是控制器负责连接数据和视图。
如下面的一个下载器类:
监听下载状态的接口,也就是MVC中的C(控制器)
public interface IDownloadApkInterProgress {
void onDownloadWait(DownloadGameInfoBean apkInfoBean);
void onDownloadStart(DownloadGameInfoBean apkInfoBean);
void onDownloadProgress(DownloadGameInfoBean apkInfoBean);
void onDownloadEnd(DownloadGameInfoBean dib);
void onDownloadFailed(DownloadGameInfoBean apkInfoBean, String errMsg);
void onDownloadPaused(DownloadGameInfoBean apkInfoBean);
void onDownloadDelete(DownloadGameInfoBean apkInfoBean);
}
处理下载的业务逻辑并通过IDownloadApkInterProgress 接口输出下载进度信息,也就是MVC中的M(模型)
public class DownloadApkRequest extends IRequest {
private Context mContext;
private Handler mHandler;
private BaseGameInfoBean mBaseGameInfoBean;
private IDownloadApkInterProgress mListener;
private DownloadManager.IDownloadPause mPauseListener;
private long mProgressUpdateTime = 0;
private long mProgressUpdatePos = 0;
private boolean mIsRunning = false;
private long mDateTime;
private long mCurrentTime;
private int mFrom;//在哪个界面点击下载
public DownloadApkRequest(Context context, Handler handler, int from,BaseGameInfoBean baseGameInfoBean, IDownloadApkInterProgress listener) {
mContext = context;
mHandler = handler;
mBaseGameInfoBean = baseGameInfoBean;
mListener = listener;
mFrom = from;
init();
}
private void init() {
infoBean = new DownloadGameInfoBean();
infoBean.setSavePath(CommonHelper.getApkPath(ShuoWanApplication.getAppContext(),mBaseGameInfoBean.getGameName()));
infoBean.setState(DownloadManager.TO_DOWNLOAD);
infoBean.setCurrentPos(0);
infoBean.setEndPos(mBaseGameInfoBean.getGameSize());
//基础信息
infoBean.setGameId(mBaseGameInfoBean.getGameId());
infoBean.setGameName(mBaseGameInfoBean.getGameName());
infoBean.setPkgName(mBaseGameInfoBean.getPkgName());
infoBean.setGameVersionName(mBaseGameInfoBean.gameVersionName);
infoBean.setVersionCode(mBaseGameInfoBean.versionCode);
infoBean.setGameDownloadUrl(mBaseGameInfoBean.gameDownloadUrl);
infoBean.setGameIconUrl(mBaseGameInfoBean.gameIconUrl);
infoBean.setGameDownloadNum(mBaseGameInfoBean.gameDownloadNum);
infoBean.setGameLanguage(mBaseGameInfoBean.gameLanguage);
infoBean.setGameStar(mBaseGameInfoBean.getGameStar());
infoBean.setGameScore(mBaseGameInfoBean.getGameScore());
infoBean.setFromInterface(mFrom);
new File(infoBean.getSavePath()).delete();
notifyDownloadWait(infoBean);
}
public String getPackageName() {
return mBaseGameInfoBean.pkgName;
}
public String getUrl(){
return mBaseGameInfoBean.gameDownloadUrl;
}
@Override
public int getPriority() {
return PRIORITY.PRIORITY_LOW;
}
@Override
public boolean execute() throws Exception {
//获取provider的状态,根据状态下载
mIsRunning = true;
infoBean.setNetState(CommonHelper.isNetworkAvailable(mContext) ? CommonHelper.isWifi(mContext) ? CommonHelper.NET_WIFI : CommonHelper.NET_MOBILE: CommonHelper.NET_ERROR);
infoBean.setSpeed(0);
File saveFile = null;
InputStream inStream = null;
BufferedRandomAccessFile raFile = null;
try {
saveFile = new File(infoBean.getSavePath());
if (!saveFile.exists()) {
saveFile.createNewFile();
}
long startPos = saveFile.length();
long avTotalSize = Storage.recordAvailableSpace(mContext);
//如果空间不足
if (avTotalSize <= mBaseGameInfoBean.gameSize - startPos) {
infoBean.setState(DownloadManager.DOWNLOAD_MEMORY_OUT);
notifyDownloadFailed(infoBean, "空间不足");
return false;
}
//连接服务器下载文件
URL httpUrl = new URL(infoBean.gameDownloadUrl.replaceAll(" ", "%20"));
HttpURLConnection http = (HttpURLConnection) httpUrl.openConnection();
http.setConnectTimeout(5 * 1000);
http.setRequestMethod("GET");
http.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"); //设置客户端可以接受的返回数据类型
http.setRequestProperty("Accept-Language", "zh-CN"); //设置客户端使用的语言问中文
http.setRequestProperty("Referer", mBaseGameInfoBean.gameDownloadUrl); //设置请求的来源,便于对访问来源进行统计
http.setRequestProperty("Charset", "UTF-8"); //设置通信编码为UTF-8
http.setRequestProperty("Range", "bytes=" + startPos + "-");
http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); //客户端用户代理
http.setRequestProperty("Connection", "Keep-Alive"); //使用长连接
inStream = http.getInputStream();
//http.getContentLength()获得从startPos开始到结尾的长度,所以要加上startPos才是总长度
infoBean.setEndPos(http.getContentLength() + startPos);
infoBean.setCurrentPos(startPos);
infoBean.setState(DownloadManager.DOWNLOADING);
notifyDownloadStart(infoBean);//通知开始下载
byte[] buffer = new byte[1024 * 32]; //设置本地数据缓存的大小为32k
int offset = 0;
raFile = new BufferedRandomAccessFile(saveFile, "rwd");
raFile.seek(startPos);
mProgressUpdatePos = startPos;
while (mIsRunning && (offset = inStream.read(buffer, 0, buffer.length)) != -1) {
raFile.write(buffer, 0, offset);
mCurrentTime = System.currentTimeMillis();
infoBean.setCurrentPos(infoBean.getCurrentPos() + offset);
mDateTime = mCurrentTime - mProgressUpdateTime;
if(mDateTime >300){
long speed = (infoBean.getCurrentPos() - mProgressUpdatePos)*1000/mDateTime;
if(speed < 0){
speed = 0;
}
infoBean.setSpeed(speed);
mProgressUpdatePos = infoBean.getCurrentPos();
mProgressUpdateTime = mCurrentTime;
//控制界面进度刷新频率
notifyDownloadProgress(infoBean); //通知进度更新
}
}
if (!mIsRunning) {
infoBean.setState(DownloadManager.DOWNLOAD_PAUSE);
notifyDownloadPause(infoBean);//通知暂停下载
} else {
infoBean.setState(DownloadManager.DOWNLOADED);
notifyDownloadDone(infoBean);//通知下载完成
}
raFile.close();
inStream.close();
if(TextUtils.isEmpty(infoBean.getPkgName())){
String pkg = CommonHelper.getPkgByPath(mContext,infoBean.getSavePath());
if(!TextUtils.isEmpty(pkg)){
infoBean.setPkgName(pkg);
notifyDownloadDone(infoBean);
}
}
} catch (Exception e) {
infoBean.setState(DownloadManager.DOWNLOAD_ERROR);
notifyDownloadFailed(infoBean, "下载错误");
try {
if (raFile != null) raFile.close();
if (inStream != null) inStream.close();
} catch (Exception e1) {
}
e.printStackTrace();
}
return false;
}
public void notifyDownloadPause(final DownloadGameInfoBean apkInfoBean) {
if (mPauseListener != null) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onDownloadPaused(apkInfoBean);
}
mPauseListener.onPaused();
}
});
} else {
if (mListener != null) {
mListener.onDownloadPaused(apkInfoBean);
}
mPauseListener.onPaused();
}
} else if (mListener != null) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDownloadPaused(apkInfoBean);
}
});
} else {
mListener.onDownloadPaused(apkInfoBean);
}
}
}
public void exit(DownloadManager.IDownloadPause listener) {
mPauseListener = listener;
if (mPauseListener != null) {
mPauseListener.onPauseing();
}
mIsRunning = false;
}
private void notifyDownloadStart(final DownloadGameInfoBean apkInfoBean) {
if (mListener != null) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDownloadStart(apkInfoBean);
}
});
} else {
mListener.onDownloadStart(apkInfoBean);
}
}
}
private void notifyDownloadWait(final DownloadGameInfoBean apkInfoBean) {
if (mListener != null) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDownloadWait(apkInfoBean);
}
});
} else {
mListener.onDownloadWait(apkInfoBean);
}
}
}
private void notifyDownloadProgress(final DownloadGameInfoBean apkInfoBean) {
if (mListener != null) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDownloadProgress(apkInfoBean);
}
});
} else {
mListener.onDownloadProgress(apkInfoBean);
}
}
}
private void notifyDownloadDone(final DownloadGameInfoBean apkInfoBean) {
if (mListener != null) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDownloadEnd(apkInfoBean);
}
});
} else {
mListener.onDownloadEnd(apkInfoBean);
}
}
}
private void notifyDownloadFailed(final DownloadGameInfoBean apkInfoBean, final String errMsg) {
if (mListener != null) {
if (mHandler != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDownloadFailed(apkInfoBean, errMsg);
}
});
} else {
mListener.onDownloadFailed(apkInfoBean, errMsg);
}
}
}
public boolean getIsRunning(){
return mIsRunning;
}
}
最后就是在需要知道下载进度信息的界面接收下载数据也就是MVC中的V(视图)
public DownloadActivity extends BaseActivity implements IDownloadApkInterProgress {
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new DownloadApkRequest(context, handler, from,baseGameInfoBean, this).execute();}
@Overridepublic void onDownloadStart(DownloadGameInfoBean apkInfoBean) { }@Overridepublic void onDownloadProgress(DownloadGameInfoBean apkInfoBean) { }@Overridepublic void onDownloadEnd(DownloadGameInfoBean apkInfoBean) { } @Overridepublic void onDownloadFailed(DownloadGameInfoBean apkInfoBean, String errMsg) { }@Overridepublic void onDownloadPaused(DownloadGameInfoBean apkInfoBean) { }@Overridepublic void onDownloadWait(DownloadGameInfoBean apkInfoBean) { }@Overridepublic void onDownloadDelete(DownloadGameInfoBean apkInfoBean) { }@Overridepublic void onInstall(String pkg) { }@Overridepublic void onRemove(String pkg) { }
}
这是一个比较明显的例子,在遇到下载的功能时由于还需要很多其他操作(比如数据库操作),往往还比较容易想到要单独封装出来。往往是一些看似很简单的功能却容易疏忽了。比如跳转Activity,很多人觉得跳转个Activity这么简单的事情就直接写在Activity里面就行了,何必还要封装这么麻烦。但是,当Activity越来越多,相互之间跳转越频繁时,问题就出来了。我写的这几个Activity要跳转到ActivityDemo,你写的几个Actiivty也要跳转到ActivityDemo。然后在ActivityDemo接收intent传来的参数的时候,我写两个参数,你写两个参数。突然有一天会发现在跳转到ActivityDemo的时候出现了空指针错误。原因就是他在跳转ActivityDemo的时候Intent里没有传我在ActivityDemo里面要获取的参数。他在写跳转的时候根本不知道你在别的地方也写了跳转ActivityDemo的代码,所以也不知道要传你那几个参数。所以比较好的办法就是封装一个管理跳转方法的类。
public class ActivityUtils {
/** * 游戏详情(普通) * * @param context * @param baseGameInfoBean */public static void startNormalGameDetailActivity(Context context, BaseGameInfoBean baseGameInfoBean, String gameId) { Intent intent = new Intent(context, NormalGameDetailActivity.class); intent.putExtra(NormalGameDetailActivity.EXTRA_GAME, baseGameInfoBean); intent.putExtra(NormalGameDetailActivity.EXTRA_GAME_ID, gameId); ((Activity)context).startActivityForResult(intent,0);}public static void startTaskGameDetailActivity(Context context, BaseGameInfoBean baseGameInfoBean) { Intent intent = new Intent(context, TaskGameDetailActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(TaskGameDetailActivity.EXTRA_GAME_INFO, baseGameInfoBean); context.startActivity(intent);}public static void startYinDaoActivity(Context context) { Intent intent = new Intent(context, YinDaoActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent);}
}不管是谁要实现Activity跳转都要使用ActivityUtils里面的跳转方法,那么不管是谁使用,都可以看得一清二楚要传什么参数,要注意些什么。
所以追根到底封装就是为了提高代码的可读性、可复用性、可维护性、可扩展性。
- Android编程思想,面向对象程序设计第六篇——封装(下)功能模块化,MVC分离
- Android编程思想,面向对象程序设计第六篇——封装(上)布局模块化
- Android编程思想,面向对象程序设计第五篇——继承(下)业务逻辑抽象化
- Android编程思想,面向对象程序设计第二篇——单例模式
- Android编程思想,面向对象程序设计第三篇——观察者模式
- 面向对象编程思想---封装
- Android编程思想,面向对象程序设计第一篇——设计模式6个原则
- Android编程思想,面向对象程序设计第四篇——继承(上)重复代码放在基类
- 封装,面向对象设计编程思想
- 程序设计基础——面向对象程序设计思想
- JAVA进阶 面向对象程序设计——第7周 控制反转与MVC模式(数据,表现,控制,分离)
- 面向对象程序设计思想
- 面向对象程序设计思想
- iOS—学习面向对象编程思想
- 重温面向对象的思想OOP——封装
- JavaScript面向对象编程——封装
- 面向对象编程,我的思想(下)
- 面向对象编程,我的思想[下]
- 加密盐的意义和用途
- LinuxC下Makefile规则执行顺序
- 如何配置Hadoop集群?(图片待补充)
- 1013. Battle Over Cities (25)
- 数据结构实验之排序六:希尔排序
- Android编程思想,面向对象程序设计第六篇——封装(下)功能模块化,MVC分离
- iOS开发 - 需要加密key的SHA256和MD5加密
- iOS GCD子线程调用主线程刷新
- centos6.8搭建DNS服务器(bind)
- consistent gets
- C# MEF 通用插件框架
- Java字符串分割(split)
- 解决 javax.net.ssl.SSLHandshakeException异常
- Win32下删除目录(包含文件和子文件夹)