1、mvc mvp
由於mvc下的Controller(也就是Activity)非常的臃腫,不僅要管理視圖相關,還要處理一部分邏輯,於是就有了mvp的出現,將Activity看成視圖,讓他僅僅管理視圖相關的工作,Activity不再和業務直接發生關係,
將與業務發生關係的代碼從Activity中抽出,放在presenter 中。
看過別人寫的關於mvp的博客,自己不寫一遍,覺得還是懵懵懂懂,hongyang有一個登陸的例子,http://blog.csdn.net/lmj623565791/article/details/46596109
我覺得寫的挺好的,在理解之後,我自己實現了一個demo,功能很簡單就 是下載一個文件到本地,然後顯示進度條,下載結束後對話框告知用戶,下載出錯了也會對話框提示哪裏錯了。
地址如下:
https://github.com/yuzhiyun/MVPDownloadFile
注意:運行demo之後,下載的文件在sd卡根目錄(Environment.getExternalStorageDirectory())下。
圖解
根據自己寫的demo我自己又畫了一個圖
包結構
代碼解釋
IDownloadFileView.java
這是view層的接口,view實現這個接口中對view的操作函數
public interface IDownloadFileView {
String getUrl();
void showErrorDialog(String error);
void showSuccessDialog();
void changeProgress(int progress);
}
MainActivity.java
view層,實現IView接口,實現對view的操作函數;
view關聯一個presenter,並且把對IView的實現傳遞給presenter。這樣,presenter就可以通過IView操作UI了。
public class MainActivity extends BaseActivity implements View.OnClickListener,IDownloadFileView {
Button btn_download;
EditText et_url;
ProgressBar progressBar;
DownloadPresenter downloadPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void setViewForActivity() {
setContentView(R.layout.activity_main);
}
@Override
protected void findViewByIds() {
btn_download= (Button) findViewById(R.id.btn_download);
et_url= (EditText) findViewById(R.id.et_url);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
}
@Override
protected void setListeners() {
btn_download.setOnClickListener(this);
}
@Override
protected void initOther() {
downloadPresenter=new DownloadPresenter(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_download:
downloadPresenter.startDownLoad();
break;
}
}
/**
* 獲取下載鏈接
* @return
*/
@Override
public String getUrl() {
// return ;
return et_url.getText().toString().trim();
}
@Override
public void showErrorDialog(String error) {
//Toast.makeText(this,error,Toast.LENGTH_LONG);
//Log.i("MainActivity",error);
showDialog(error);
}
@Override
public void showSuccessDialog() {
// Toast.makeText(MainActivity.this,"下載成功",Toast.LENGTH_LONG);
showDialog("下載成功");
//Log.i("MainActivity","下載成功");
}
@Override
public void changeProgress(int progress) {
progressBar.setProgress(progress);
}
/**
* 彈出對話框
*
* @param msg
*/
public void showDialog(String msg) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("返回結果:\n" + msg)
.setCancelable(false)
.setPositiveButton("確認", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
builder.create().show();
}
}
DownloadPresenter.java
presenter持有iview接口(IDownloadFileView)以及model層的業務類(IDownloadFileBiz),這樣presenter先調用model 完成業務,再把反饋結果顯示到UI 上。
public class DownloadPresenter {
IDownloadFileView downloadFileView;
IDownloadFileBiz downloadFileBiz;
public DownloadPresenter(IDownloadFileView iDownloadFileView){
downloadFileView=iDownloadFileView;
downloadFileBiz=new DownloadBiz();
}
public void startDownLoad(){
downloadFileBiz.startDownload(downloadFileView.getUrl(), new OnDownloadListener() {
@Override
public void OnError(String error) {
downloadFileView.showErrorDialog(error);
}
@Override
public void OnSuccess() {
downloadFileView.showSuccessDialog();
}
@Override
public void OnProgress(Integer progress) {
downloadFileView.changeProgress(progress);
}
});
}
}
DownloadBiz.java
Model層的業務類,依賴presenter傳遞過來的OnDownloadListener最終把執行結果反饋到UI上
public class DownloadBiz implements IDownloadFileBiz {
@Override
public void startDownload(String url, OnDownloadListener downloadListener) {
new DownLoadAsynctask(downloadListener).execute(url);
}
}
class DownLoadAsynctask extends AsyncTask<String,Integer,String>{
OnDownloadListener downloadListener;
DownLoadAsynctask(OnDownloadListener downloadListener){
this.downloadListener=downloadListener;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... strings) {
double now_length=0;
double sum_length=0;
String filename="";
boolean isPaused = false;
File file = null;
int startIndex = 0,endIndex=0;
try {
byte[] bytes = new byte[1024];
URL url = null;
HttpURLConnection conn = null;
url = new URL(strings[0]);
conn = (HttpURLConnection) url.openConnection();
endIndex = conn.getContentLength();
System.out.println("獲得輸入流");
InputStream is = conn.getInputStream();
System.out.println("輸入流完畢");
sum_length = endIndex;
filename = strings[0].substring(strings[0].lastIndexOf("/")+1);
file = new File(Environment.getExternalStorageDirectory(),filename);
/**
* RandomAccessFile可以訪問文件的任意位置
* "r" 以只讀方式打開。調用結果對象的任何 write 方法都將導致拋出 IOException。
* "rw" 打開以便讀取和寫入。
* "rws" 打開以便讀取和寫入。相對於 "rw","rws" 還要求對“文件的內容”或“元數據”的每個更新都同步寫入到基礎存儲設備。
* "rwd" 打開以便讀取和寫入,相對於 "rw","rwd" 還要求對“文件的內容”的每個更新都同步寫入到基礎存儲設備。
* 明白?
*/
RandomAccessFile raf1 = new RandomAccessFile(file,"rwd");
System.out.println("開始寫入");
raf1.seek(startIndex);
now_length += startIndex;
int i =1;
int len =0;
while (((len=is.read(bytes))!=-1)&&!isPaused){
System.out.println("第"+i+"次讀入");
raf1.write(bytes, 0, len);
System.out.println("第" + i + "次寫入");
now_length+=len;
i++;
publishProgress((int)(now_length/sum_length *100));
}
System.out.println("寫入完畢");
raf1.close();
conn.disconnect();
} catch (IOException e) {
e.printStackTrace();
return e.toString();
}
return "success";
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(s.equals("success"))
downloadListener.OnSuccess();
else
downloadListener.OnError(s);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
downloadListener.OnProgress(values[0]);
}
}