從零開始搭建一個主流專案框架(一)—簡單的框架
個人部落格:haichenyi.com。感謝關注
目的
首先先說出,最終的目的是現在主流的MVP+RxJava+Retrofit+OkHttp框架。讓大家心裡有底
開發工具Android Studio3.0,還在用eclipse的同鞋,強烈推薦你跨出這一步,你會發現一個新的世界。android studio都出來這麼久了,你還在遠古時代做開發,說句不好聽的,你完全與時代脫軌,你不適合做開發(純屬個人觀點)
本篇就只有三部分,第一部分就是新建一個Application,第二部分就是BaseActivity,第三部分就是BaseFragment
Application
首先你得有application類,去初始化應用只用初始化一次的內容,繼承Application,然後在清單檔案裡面註冊。
package com.haichenyi.myproject;
import android.app.Application;
import com.squareup.leakcanary.LeakCanary;
/**
* Author: 海晨憶
* Date: 2018/2/23
* Desc:
*/
public class MyApplication extends Application {
private static MyApplication instance;
public static MyApplication getInstance() {
return instance;
}
private void setInstance(MyApplication instance) {
MyApplication.instance = instance;
}
@Override
public void onCreate() {
super.onCreate();
setInstance(this);
initLeakCanary();
}
/**
* 初始化記憶體檢測工具
*/
private void initLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this )) {
return;
}
LeakCanary.install(this);
}
}
如上程式碼,我這裡就初始化了一個全域性application單例物件,還初始化square公司出品的一個記憶體檢測工具,用於檢測你專案中記憶體洩漏情況。便於你優化專案。
如上圖所示,這個就是清單檔案,在application結點下面,新增name標籤,內容就是你建立的application的名字。這裡你還需要新增兩個記憶體檢測的依賴。
如上圖所示,首先把你的專案結構檢視切換到Project,開啟你的app目錄下的build.gradle檔案,在dependencies結點下面(只要是新增開源庫都是在該結點下面,後面就不說了),新增如下兩行程式碼:
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
最後的1.5.4是版本號,你可以在github上面搜尋leakcanary,找最新的版本
BaseActivity
建立基類BaseActivity,也就是所有Activity的父類。還有一個基類的介面BaseView,BaseActivity繼承剛才新增的依賴的SupportActivity類,實現BaseView介面,並且實現點選事件的介面(選擇實現,你要是不樂意在基類裡面寫,你可以在你自己的子類裡面重新實現一遍也是可以的)。程式碼如下:每個方法註釋寫的很清楚,就不用一一解釋了
package com.haichenyi.myproject.base;
import android.app.AlertDialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.Window;
import android.widget.ProgressBar;
import com.haichenyi.myproject.utils.ToastUtils;
import me.yokeyword.fragmentation.SupportActivity;
/**
* Author: 海晨憶
* Date: 2018/2/23
* Desc:
*/
public abstract class BaseActivity extends SupportActivity implements BaseView {
private AlertDialog loadingDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
/**
* Toast 提示使用者
* @param msg 提示內容String
*/
@Override
public void showTipMsg(String msg) {
ToastUtils.showTipMsg(msg);
}
/**
* Toast 提示使用者
* @param msg 提示內容res目錄下面的String的int值
*/
@Override
public void showTipMsg(int msg) {
ToastUtils.showTipMsg(msg);
}
/**
* 網路請求的時候顯示正在載入的對話方塊
*/
@Override
public void showLoading() {
if (null == loadingDialog) {
loadingDialog = new AlertDialog.Builder(this).setView(new ProgressBar(this)).create();
loadingDialog.setCanceledOnTouchOutside(false);
Window window = loadingDialog.getWindow();
if (null != window) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
}
if (!loadingDialog.isShowing()) {
loadingDialog.show();
}
}
/**
* 網路請求完成時隱藏載入對話方塊
*/
@Override
public void hideLoading() {
if (null != loadingDialog) {
if (loadingDialog.isShowing()) {
loadingDialog.dismiss();
}
loadingDialog = null;
}
}
@Override
public void invalidToken() {
//用於檢測你當前使用者的token是否有效,無效就返回登入介面,具體的業務邏輯你自己實現
//如果需要做到實時檢測,推薦用socket長連線,每隔10秒傳送一個驗證當前登入使用者token是否過期的請求
}
/**
* Finish當前頁面,最好實現onBackPressedSupport(),這個方法會有一個退棧操作,
* 開源框架實現的,我們不用管
*/
@Override
public void myFinish() {
onBackPressedSupport();
}
@Override
public void onBackPressedSupport() {
super.onBackPressedSupport();
}
}
上面是目前BaseActivity程式碼,註釋寫的很清楚,你會發現BaseView你並沒有,下面我給出BaseView的程式碼
package com.haichenyi.myproject.base;
import android.support.annotation.StringRes;
/**
* Author: 海晨憶
* Date: 2018/2/23
* Desc:
*/
public interface BaseView {
void showTipMsg(String msg);
void showTipMsg(@StringRes int msg);
void showLoading();
void hideLoading();
void invalidToken();
void myFinish();
}
BaseView就是一個介面,是所有V層的基類,程式碼很簡單,Toast方法,顯示隱藏載入的對話方塊方法,檢驗token是否過期的方法,finish當前頁面的方法。什麼?Toast方法你沒有,下面我貼出來我的Toast的工具類
/**
* Author: 海晨憶.
* Date: 2017/12/21
* Desc: 實時更新的Toast工具類
*/
public final class ToastUtils {
private static Toast toast;
private ToastUtils() {
throw new RuntimeException("工具類不允許建立物件");
}
@SuppressWarnings("all")
private static void init() {
if (toast == null) {
toast = Toast.makeText(MyApplication.getInstance(), "", Toast.LENGTH_SHORT);
}
}
public static void showTipMsg(String msg) {
if (null == toast) {
init();
}
toast.setText(msg);
toast.show();
}
public static void showTipMsg(@StringRes int msg) {
if (null == toast) {
init();
}
toast.setText(msg);
toast.show();
}
}
上面我貼出了三個類,這裡我要說明的是,我又建立了兩個package,一個是base,一個是utils,我把BaseActivity,BaseView,MyApplication放在base包下面,Toast的工具類放在utils包下面
再就是新增一些常用的東西了,這裡我沒有用黃油刀,用過一段時間之後,感覺他的每個控制元件都是全域性的,有點佔記憶體,就放棄了。我下面貼出BaseActivity新增的虛擬碼:
/**
* 儲存當前activity物件,在OnCreate裡面新增,記得在OnDestroy裡面移除
* 有什麼用呢?
* 比方說有一個需求,讓你在任意位置彈出對話方塊,彈對話方塊又需要一個context物件,這個時候,
* 你就只用傳當前list的最上層的activity物件就可以了
* 當然還有其他需求
*/
public static List<BaseActivity> activities = new ArrayList<>();
private Toolbar toolbar;
private TextView tvToolbarTitle;
private TextView tvToolbarRight;
private TextView tvBack;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activities.add(this);
//強制豎屏(不強制加)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
int layoutId = getLayoutId(savedInstanceState);
View inflate = getLayoutInflater().inflate(R.layout.activity_base, toolbar, false);
LinearLayout rootLinearLayout = inflate.findViewById(R.id.ll_layout_base_activity);
//沒有佈局的時候傳0
if (0 == layoutId) {
setContentView(rootLinearLayout);
} else {
View rootView = getLayoutInflater().inflate(layoutId, rootLinearLayout, true);
setContentView(rootView);
}
stateBar();
initView();
initData();
setOnClick(R.id.tv_back_base_activity);
}
/**
* 設定點選事件.
*
* @param ids 被點選View的ID
* @return {@link BaseActivity}
*/
public BaseActivity setOnClick(@IdRes int... ids) {
View view;
for (int id : ids) {
view = findViewById(id);
if (null != view) {
view.setOnClickListener(this);
}
}
return this;
}
/**
* 設定點選事件.
*
* @param views 被點選View
* @return {@link BaseActivity}
*/
public BaseActivity setOnClick(View... views) {
for (View view : views) {
view.setOnClickListener(this);
}
return this;
}
/**
* 獲取當前佈局物件
*
* @param savedInstanceState 這個是當前activity儲存的資料,最常見的就是橫豎屏切換的時候,
* 資料丟失問題
* @return 當前佈局的int值
*/
protected abstract int getLayoutId(Bundle savedInstanceState);
@Override
protected void onDestroy() {
activities.remove(this);
super.onDestroy();
}
protected void initData() {
}
protected void initView() {
toolbar = findViewById(R.id.toolbar_base_activity);
tvToolbarTitle = findViewById(R.id.tv_title_base_activity);
tvToolbarRight = findViewById(R.id.tv_right_base_activity);
}
/**
* 設定狀態列背景顏色,不能改變狀態列內容的顏色
*/
private void stateBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setNavigationBarTintEnabled(true);
tintManager.setTintColor(Color.parseColor("#000000"));
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_back_base_activity:
onBackPressedSupport();
break;
default:
break;
}
}
這裡我需要說明的是,新增了一個開源框架,就是設定狀態列背景顏色的systembartint。
implementation 'com.readystatesoftware.systembartint:systembartint:1.0.3'
再就是設定activity標題內容,左邊,右邊的內容,左邊右邊可能是文字,也可能是圖片。所以,我在用的時候,都是用的TextView,ImageView,不能設定文字。方法如下:
public BaseActivity setTitles(CharSequence title) {
tvToolbarTitle.setText(title);
return this;
}
/**
* 初始化toolbar的內容
* @param isShowToolbar 是否顯示toolbar
* @param isShowBack 是否顯示左邊的TextView
* @param isShowMore 是否顯示右邊的TextView
* @return 當前activity物件,可以連點
*/
protected BaseActivity initToolbar(boolean isShowToolbar, boolean isShowBack,
boolean isShowMore) {
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (null != actionBar) {
if (isShowToolbar) {
actionBar.show();
tvBack = findViewById(R.id.tv_back_base_activity);
TextView textView = findViewById(R.id.tv_right_base_activity);
if (null != tvBack && null != textView) {
tvBack.setVisibility(isShowBack ? View.VISIBLE : View.INVISIBLE);
textView.setVisibility(isShowMore ? View.VISIBLE : View.INVISIBLE);
}
} else {
actionBar.hide();
}
}
return this;
}
public BaseActivity setToolbarBack(int colorId) {
toolbar.setBackgroundColor(getResources().getColor(colorId));
return this;
}
@SuppressWarnings("unused")
public BaseActivity setMyTitle(String title) {
tvToolbarTitle.setText(title);
return this;
}
public BaseActivity setMyTitle(@StringRes int stringId) {
tvToolbarTitle.setText(stringId);
return this;
}
public void setMoreTitle(String moreTitle) {
tvToolbarRight.setText(moreTitle);
}
public BaseActivity setMoreTitle(@StringRes int stringId) {
tvToolbarRight.setText(stringId);
return this;
}
/**
* 設定左邊內容.
*
* @param leftTitle 內容
* @return {@link BaseActivity}
*/
public BaseActivity setLeftTitle(String leftTitle) {
if (tvBack != null) {
tvBack.setBackground(null);
tvBack.setText(leftTitle);
}
return this;
}
/**
* 設定左邊內容.
*
* @param leftTitle 內容
*/
public void setLeftTitle(@StringRes int leftTitle) {
if (tvBack != null) {
tvBack.setBackground(null);
tvBack.setText(leftTitle);
}
}
@SuppressWarnings("unused")
protected BaseActivity setMoreBackground(int resId) {
tvToolbarRight.setBackgroundResource(resId);
return this;
}
可以看到上面的方法返回值都是BaseActivity,這樣做的目的就只有一個,可以連點,寫一個方法之後,可以接著點寫下一個方法,不用寫一個方法就要加分號,就換一行寫下一個方法。
還要加一句,在你的app主題裡面新增兩個item,也就是你的res目錄下面的style:
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
我這裡貼出我目前的style的圖片
下面有一個LineHorizontal樣式,就是你toolbar下面的那個橫線
BaseFragment
BaseFragment跟BaseActivity的邏輯是差不多的,我這裡就貼出程式碼
package com.haichenyi.myproject.base;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.haichenyi.myproject.utils.ToastUtils;
import me.yokeyword.fragmentation.SupportFragment;
/**
* Author: 海晨憶
* Date: 2018/2/23
* Desc:
*/
public abstract class BaseFragment extends SupportFragment implements BaseView,
View.OnClickListener {
protected boolean isInit;
private View rootView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
int layoutRes = layoutRes();
if (0 != layoutRes) {
return inflater.inflate(layoutRes, null);
} else {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
rootView = view;
}
@Override
public void onLazyInitView(@Nullable Bundle savedInstanceState) {
super.onLazyInitView(savedInstanceState);
isInit = true;
init();
}
protected <T extends View> T findViewById(@IdRes int id) {
return rootView.findViewById(id);
}
/**
* 設定點選事件.
*
* @param ids 被點選View的ID
* @return {@link BaseFragment}
*/
public BaseFragment setOnClick(@IdRes int... ids) {
for (int id : ids) {
rootView.findViewById(id).setOnClickListener(this);
}
return this;
}
/**
* 設定點選事件.
*
* @param views 被點選View的ID
* @return {@link BaseFragment}
*/
public BaseFragment setOnClick(View... views) {
for (View view : views) {
view.setOnClickListener(this);
}
return this;
}
protected abstract void init();
@Override
public void onDestroy() {
rootView = null;
super.onDestroy();
}
protected abstract int layoutRes();
@Override
public void showTipMsg(String msg) {
ToastUtils.showTipMsg(msg);
}
@Override
public void showTipMsg(int msg) {
ToastUtils.showTipMsg(msg);
}
@Override
public void showLoading() {
BaseActivity activity = (BaseActivity) getActivity();
/*if (activity instanceof BaseMvpActivity) {
activity.showLoading();
}*/
}
@Override
public void hideLoading() {
BaseActivity activity = (BaseActivity) getActivity();
/*if (activity instanceof BaseMvpActivity) {
activity.hideLoading();
}*/
}
@Override
public void invalidToken() {
BaseActivity activity = (BaseActivity) getActivity();
/*if (activity instanceof BaseMvpActivity) {
activity.invalidToken();
}*/
}
@Override
public void onClick(View v) {
}
@Override
public void myFinish() {
onBackPressedSupport();
}
}
兩者在佈局抽象方法裡面有一點區別,Activity的傳了Boundle引數,Fragment沒有傳,因為Fragment可以通過getArguments()方法獲取到這個物件,而Activity不能獲取到。
總結
到此,一個簡單的專案框架就出來了,目前還是框架的第一步,是一個雛形,還不包括MVP,dagger等等,下一篇就加上MVP,我這個人有個好習慣,就是喜歡寫註釋,我註釋寫的很清楚,是幹什麼用的,我也衷心的希望,你能寫好註釋。
相關推薦
從零開始搭建一個簡易的伺服器(一)
前言 其實大家大可不必被伺服器這三個字嚇到,一個入門級後端框架,所需的僅僅是HTTP相關的知識與應用這些知識的程式設計工具。據本人的經驗,絕大多數人擁有搭建後端所涉及到的基礎理論知識,但是缺乏能將之應用出去的工具,而本文即是交給讀者這樣一個工具,並能夠運用之來
從零開始搭建一個主流專案框架(三)—RxJava2.0+Retrofit2.0+OkHttp
個人部落格:haichenyi.com。感謝關注 上一篇,我們把mvp+dagger加進去了,這一篇,我們把網路請求加上 我這裡的網路請求是用的裝飾者模式去寫的,什麼是裝飾者模式呢?在不必改變原類檔案和使用繼承的情況下,動態地擴充套件一個物件的功能。
從零開始搭建一個主流專案框架(一)—簡單的框架
個人部落格:haichenyi.com。感謝關注 目的 首先先說出,最終的目的是現在主流的MVP+RxJava+Retrofit+OkHttp框架。讓大家心裡有底 開發工具Android Studio3.0,還在用eclipse的同鞋,強烈推薦
從零開始搭建一個主流專案框架(二)—MVP+Dagger2
個人部落格:haichenyi.com。感謝關注 接著上一篇簡單的框架,沒有看過的同鞋可以去喵一眼。上一篇我們搭好了簡單的框架,初始化一次的內容丟在Application裡面,所有的activity繼承一個類BaseActivity,還有Fragment繼
從零開始搭建一個簡易的伺服器(二)
超級大坑 第一篇部落格到現在拖坑有半年了(不過估計也沒人記得我),原本的打算是既然要寫伺服器,那自然要設計一門語言,類似於php這樣的工作於伺服器後端負責後端渲染,然後到目前為止的時間基本都花在寫編譯器上了囧,編譯器的專案在這裡。如果真的等編譯器全部寫
從零開始造一個Markdown編輯器(一)
實時 需要 自己實現 自己 背景 學習正則表達式 tex ID img 背景 最近學習正則表達式,於是要挑一個練手項目,恰好對markdown編輯器十分感興趣,於是就進行了一些常識。做了一個簡單的markdown解析器和編輯器。 網頁端的地址(不支持文件的操作): http
從零開始搭建 gRPC 服務 - Golang 篇(一)
gRPC:一個高效能、開源的通用 RPC 框架,基於標準的 HTTP/2 進行傳輸,預設採用 Protocol Buffers 序列化結構化資料。本文將介紹如何從零搭建一個 Golang 的 gRPC 服務。 準備工作 本文所述的搭建環境基於滴滴雲提供的 CentOS 7.2 標準映
react開發:從零開始搭建一個react專案
從頭開始建立一個React App - 專案基本配置 npm init 生成 package.json 檔案.安裝各種需要的依賴: npm install --save react - 安裝React.npm install --save reac
簡單幾步從零開始搭建一個SSM專案
SSM(Spring+SpringMVC+MyBatis)框架集由Spring、SpringMVC、MyBatis三個開源框架整合而成,常作為資料來源較簡單的web專案的框架。並且可在此基礎上延伸擴充套件整合出很多東西。延伸部分此處就不介紹了。本篇面向的只是剛準備入門框架,
用Vue-cli從零開始搭建一個Vue專案
電腦環境準備 1、下載安裝node.js。node中會預設安裝npm。命令提示符中 npm -v可檢視安裝版本。 2、開啟命令提示符,安裝淘寶映象cnpm。因為cnpm安裝依賴包時會比npm速度快很多。安裝命令: npm install -g cnpm --regist
從零開始搭建 gRPC 服務 - Golang 篇(二)
在從零開始搭建 gRPC 服務 - Golang 篇(一)中介紹瞭如何搭建 gRPC 環境並構建一個簡單的 gRPC 服務,本文將介紹 gRPC 的 streaming 。 流式 RPC gRPC 基於標準的 HTTP/2 進行傳輸,可以方便的實現 streaming 功能。要在 g
從零開始學習音視訊程式設計技術(一) 視訊格式講解(學習筆記)
/* 該型別部落格為學習時載錄筆記,加上自己對一些不理解部分自己的理解。會涉及其他博主的博文的摘錄,會標註出處 */ ==========================================================================
從零開始學習音視訊程式設計技術(一) 視訊格式講解
所謂視訊,其實就是將一張一張的圖片連續的放出來,就像放幻燈片一樣,由於人眼的惰性,因此只要圖片的數量足夠多,就會覺得是連續的動作。 所以,只需要將一張一張的圖片儲存下來,這樣就可以構成一個視訊了。 但是,由於目前網路和儲存空間的限制,直接儲存圖片顯然不可行。
從零開始學 Web 之 JavaScript 高階(一)原型,貪吃蛇案例
一、複習 例項物件和建構函式之間的關係: 1、例項物件是通過建構函式來建立的,建立的過程叫例項化。 2、如何判斷一個物件是不是某種資料型別? 通過構造器的方法。例項物件.constructor === 建構函式名字 (推薦使用)例項物件 instanceof 建構函式名字 二、原型 1、原型的引入 由
從零開始學 Web 之 移動Web(一)螢幕相關基本知識,除錯,視口,螢幕適配
一、基礎知識 1、螢幕 移動裝置與PC裝置最大的差異在於螢幕,這主要體現在螢幕尺寸和螢幕解析度兩個方面。 通常我們所指的螢幕尺寸,實際上指的是螢幕對角線的長度(一般用英寸來度量)。 而解析度則一般用畫素來度量 px,表示螢幕水平和垂直方向的畫素數,例如 1920*1080 指的是螢幕垂直方向和水平方向分別
從零開始學 Web 之 Vue.js(一)Vue.js概述,基本結構,指令,事件修飾符,樣式
大家好,這裡是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 部落格園:http://www.cnblogs.com/lvonve/ CSDN:https://blog.csdn.net/lvonve/
從零開始佈置你的個人網站(一)
準備 之前用騰訊雲的學生購買了一個1元伺服器,但是一直沒有用起來,最近專案不太忙,準備自己搭建一個線上環境。 安裝ubuntu環境 安裝ubuntu的16.04.1的32環境 登入ubuntu系統,可以直接使用騰訊雲的登入,也可以通過各種
Cordova從零開始外掛開發-支付寶外掛(一)
這兩天APP開發基本進入尾聲,但有一個最後的難題發生了,就是支付。就目前而言,大家一般都在用的手機(移動)支付方式無非就是三種; 支付寶、微信、網銀(銀聯)支付;本文著重講一下支付寶外掛的開發,其他兩種類似。 支付寶方面:需要簽約,商戶公鑰,商戶私鑰,支付寶公鑰,商戶par
【轉】從零開始學習音視訊程式設計技術(一) 視訊格式講解
轉自:http://blog.yundiantech.com/?log=blog&id=4 所謂視訊,其實就是將一張一張的圖片連續的放出來,就像放幻燈片一樣,由於人眼的惰性,因此只要圖片的數量足夠多,就會覺得是連續的動作。 所以,只需要將一張一張的圖片儲存下來
轉載:高德地圖API學習 從零開始學高德JS API(一)地圖展現
摘要:關於地圖的顯示,我想大家最關心的就是麻點圖,自定義底圖的解決方案了吧。在過去,marker大於500之後,瀏覽器開始逐漸卡死,大家都開始尋找解決方案,比如聚合marker啊,比如麻點圖啊。聚合marker裡面還有一些複雜的演算法,而麻點圖,最讓大家頭疼的,就是如何生成麻點圖,如何切圖,如何把圖片貼到地圖