1. 程式人生 > >從零開始搭建一個主流專案框架(一)—簡單的框架

從零開始搭建一個主流專案框架(一)—簡單的框架

個人部落格: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公司出品的一個記憶體檢測工具,用於檢測你專案中記憶體洩漏情況。便於你優化專案。

清單檔案.png

  如上圖所示,這個就是清單檔案,在application結點下面,新增name標籤,內容就是你建立的application的名字。這裡你還需要新增兩個記憶體檢測的依賴。

專案結構.png

  如上圖所示,首先把你的專案結構檢視切換到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的圖片

style.png

  下面有一個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.jsVue.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裡面還有一些複雜的演算法,而麻點圖,最讓大家頭疼的,就是如何生成麻點圖,如何切圖,如何把圖片貼到地圖