這禮拜基本都在忙自己專案上的事,然後之後會“重新整理”後把這部分的功能開源出來,這裡@下隊友 NeglectedByBoss
本週還是沒有停更收納庫,繼續安利:https://github.com/ddwhan0123/Useful-Open-Source-Android (把疑難雜症給拆出去了,還剩資料,工具類和自定義控制元件的細分工作)
本文簡單模擬一個讀書的業務流程,來談一下程式碼擴充性的問題。
建立模型
首先我們得 建立書的物件
1 2 3 4 5 6 7 8 9 |
public class Book { public String Name; //書名 public int PageCount; //總頁數 public int NowPage; //當前頁數 public T BookMoreMSG; //附加資訊 /** * get set等其他方法省略 */ |
因為我們讀一本書,肯定有其一些基本資訊,這裡就 設定了書名,總頁數,當然還可以有作者,出版日期等等等,我們只是例子不需要太複雜
NowPage 用來判斷讀書進展
BookMoreMSG 這是個泛型,也就是我們的補充項,讓每一本書的物件更鮮活。而讓程式碼實現也更靈活,增強了我們的擴充性,他可以是一句話 ,可以是一個物件 等等等。
讀書狀態回撥
寫的時候其實我沒有刻意的要想怎麼去假設,怎麼去設計也就是寫著寫著改著改著(這種方式本身不太好,還是建議大家在開始敲程式碼之前好好的想想怎麼做更好)
那既然讀書,肯定是要慢條斯理的,而且還肯定要有狀態於是我就讓這個讀書的行為用一個子執行緒然後讓他 .Sleep()下來模擬正在讀書的行為
先建立一個讀書狀態無非是 開始讀書,正在讀書,讀完了 那麼我們就用一個介面去實現
1 2 3 4 5 6 7 8 9 10 |
public interface ReadListener { //開始讀書 void start(); //正在讀書 void doing(T t); //讀完了 void finish(T t); } |
因為我們書有一系列的屬性,所以我們把書的狀態作為引數傳入,又因為這個介面(可能)可以在別的地方複用 所以傳入的引數還是用了泛型
填充資料
讀書之前我們得有書,所以我們得填充下資料,這本奧特曼打怪獸 我們給他一個描述語句 是神祕的反派角色 ,他總共 15頁,我們的小寶寶從頭開始讀
1 2 3 4 5 6 7 8 9 10 11 |
/* * 模擬資料 * */ private BookaddBook() { book = new Book(); book.setBookMoreMSG("神祕的反派角色"); book.setName("奧特曼打怪獸"); book.setPageCount(15); book.setNowPage(0); return book; } |
讀書的實現
讀書的狀態跟檢視(也就是Activity/Fragment)沒什麼關係,所以為了讓檢視 更 檢視 讓一個類在子執行緒去讀書吧,如果想在頁面上展示進度直接用介面傳遞就好了,So Easy!!
那我們再寫個介面,讓他作為傳播媒介告訴UI好了
1 2 3 |
public interface CommunicateListener { void setMsg(Message msg); } |
非常簡單的一個介面,傳遞一個Message物件,你想給UI傳啥都行了。
既然要實現讀書,那肯定要實現讀書狀態的回撥,那我們就來實現他
因為上面確定了,我們圖書的附加內容是一句話,那泛型的書就都成了Book
型別的Book了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class ReadImp implements ReadListener> { Book book; CommunicateListener communicate; public void setMessager(CommunicateListener communicate) { this.communicate = communicate; } public ReadImp(Book book) { this.book = book; } @Override public void start() { Log.d("--->", "ReadImp 開始讀書"); } @Override public void doing(Book book) { Log.d("--->", "現在讀到第 " + book.getNowPage() + "頁"); } @Override public void finish(Book book) { Log.d("--->", "讀完了,總共讀了 " + book.getNowPage() + "頁"); Message message = Message.obtain(); message.obj = book.getBookMoreMSG(); communicate.setMsg(message); } } |
這裡沒有讓訊息一直刷UI就 讀書讀完了 讓他 把他讀完的訊息發出去。
邏輯實現算是通了,那我們來看下UI咯
主UI
下面還有個TextView,因為一開始寶寶沒有讀完書,所以沒字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
public class MainActivity extends AppCompatActivity implements View.OnClickListener, CommunicateListener { private Button read_btn, send_text; private ReadImp readImp; private EditText edit_baobao; private ReadThread readThread; private Thread thread; private volatile Book book; private ReadBookTextView read_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { Log.d("--->", "主執行緒的 ID 是 " + Thread.currentThread().getId()); //給書賦值 addBook(); readImp = new ReadImp(book); readImp.setMessager(this); readThread = new ReadThread(book, readImp); thread = new Thread(readThread); initWidget(); } @Override protected void onStart() { super.onStart(); thread.start(); Log.d("--->", "開啟的執行緒 ID 是 " + thread.getId()); } @Override protected void onStop() { super.onStop(); thread.interrupt(); } @Override protected void onDestroy() { super.onDestroy(); thread = null; readThread = null; } private void initWidget() { read_text = (ReadBookTextView) findViewById(R.id.read_text); read_btn = (Button) findViewById(R.id.read_btn); send_text = (Button) findViewById(R.id.send_text); edit_baobao = (EditText) findViewById(R.id.edit_baobao); send_text.setOnClickListener(this); read_btn.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.read_btn: read_text.setText(""); thread.interrupt(); break; case R.id.send_text: if (edit_baobao.getText().toString().trim().length() > 0) { read_text.setText(edit_baobao.getText().toString().trim()); } break; } } @Override public void setMsg(Message msg) { read_text.setText("補充內容是 " + msg.obj.toString()); } /* * 模擬資料 * */ private BookaddBook() { book = new Book(); book.setBookMoreMSG("神祕的反派角色"); book.setName("奧特曼打怪獸"); book.setPageCount(15); book.setNowPage(0); return book; } } |
我們的MainActivity 實現了 看訊息的 CommunicateListener介面
所以在實現類讀完了書會告訴我們他要告訴我們的Message
補充下 ReadBookTextView這個類是我零時改的一個 自定義TextView,可以在子執行緒修改,之前的部落格介紹過,直接COPY過來改了改
傳送門:http://blog.csdn.net/ddwhan0123/article/details/50956307
也就是說我們讀書的過程都是在子執行緒讀的,我們讀完書的結果也是在子執行緒重新整理的UI。
OK,那整個DEMO要闡明什麼?
- 共有的一些邏輯/概念/行為,可以抽象的一定要抽象,好處在於 1省程式碼,2維護性好,3擴充性強。(這本書無論換什麼型別的描述欄位我們都可以用一套程式碼來實現,最多加不同的IMP實現,當然你可以在IMP實現上再加一層封裝,那更SO EASY了!)
- 頻繁的刷UI本身就是對MainThread進行“摧殘”,但是有些時候我們還真沒辦法,那簡單的一些刷UI的工作就可以放到子執行緒裡去做,諸如各種setText,set…set…等等等,當然這個還是要取決於 “團隊可用於子執行緒重新整理的元件的厚度”,反正是能往子執行緒丟就丟。(Rx套餐其實是把非UI的行為全挪走了,我們這裡的做法就是能分擔多少就分擔多少,充分利用現在手機多CPU的特性)
- 專案結構,其實也不用盲目的 MVC MVP MVVP什麼的,適合自己專案實際場景的才是最好的(雖然我不知道怎麼的寫著寫著這個例子有點MVP的味道)
- 多利用OOP的特性
補一些過程中的圖吧
讀書的過程
專案結構
如果有不對的地方請大家指出(肯定有很多不足的地方,但是思路大家可以參考下)。
git地址:https://github.com/ddwhan0123/BlogSample/tree/master/NumberDemo
附件下載地址:https://github.com/ddwhan0123/BlogSample/blob/master/NumberDemo/NumberDemo.zip?raw=true
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!