MVP 入門 (Android demo解析)

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]);
    }


}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章